SQL * Plus, @ und relative Pfade

9

Irgendwie scheint es, dass SQL * Plus (zumindest unter Windows) kein Skript mit einem relativen Pfad finden kann, wenn es mit aufgerufen wird @@und wenn der Pfad mit einem einzelnen oder doppelten Punkt beginnt.

Zum Beispiel habe x:\some\whereich unter folgende Verzeichnisstruktur:

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

Das heißt: zwei, script.sqlaber an verschiedenen Orten.

Der Inhalt von script.sqlknapp unter x:\some\whereist einfach

prompt SCRIPT root

während der script.sqlInhalt des anderen ist

prompt SCRIPT main-dir/main-subdir

call-script.sql liest

@@script.sql
@ script.sql

erwartete Ausgabe

Wenn ich SQL * Plus von starte x:\some\whereund dann a

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

Die Ausgabe wird sein

SCRIPT main-dir/main-subdir
SCRIPT root 

Dies wird erwartet, da die Single @Pfade suchen soll, von denen aus SQL * Plus gestartet wurde, und @@Pfade aus dem Verzeichnis des enthaltenen Skripts suchen soll.

unerwartete Ausgabe

Nun , wenn ich das ändere call-scripts.sql:

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

Das Double @@scheint sein Verhalten zu ändern, indem es nach Pfaden sucht, von denen aus SQL * Plus gestartet wurde, und die Ausgabe nun erfolgt

SCRIPT root
SCRIPT root

Das ist nicht , was ich erwartet hatte.


Ist dieses Verhalten irgendwo dokumentiert und, was noch wichtiger ist, wie muss ich es ändern, call-scripts.sqldamit es relative Pfade ( @@../../other-dir/other-sub-dir/script) korrekt aufruft ?

René Nyffenegger
quelle
Auf was ist Ihre SQLPATH-Umgebungsvariable eingestellt? Dies wirkt sich darauf aus, welche Verzeichnisse durchsucht werden.
Philᵀᴹ
Gleiches Verhalten unter Linux, FWIW. (Und ein kaufmännisches Und ist &, nicht @; was keinen richtigen Namen zu haben scheint ). Scheint ein Fehler zu sein, da es inkonsistent ist. Das einzige, was mir in den Sinn kommt, ist, eine Variable als Skript der obersten Ebene mit dem vollständigen Pfad festzulegen und alles darauf basierend zu tun. Dies ist jedoch nur dann sehr praktisch, wenn die darunter liegende Verzeichnisstruktur festgelegt ist.
Alex Poole
Vielen Dank, dass Sie auf das @ vs kaufmännische Und hingewiesen haben ... Ich hätte es wissen sollen, aber als ich den Beitrag schrieb, habe ich nicht wirklich darauf geachtet. Es ist jetzt im Titel festgelegt.
René Nyffenegger
2
Ich habe gerade sqlplus mit angegriffen strace. Hier sind die relevanten Aufrufe: pastebin.com/cVK1QQu4 Beachten Sie, dass nicht versucht wurde, "script.sql" -Dateien in anderen Verzeichnissen zu statisieren oder darauf zuzugreifen, bevor versucht wurde, die in der Pastebin-Ausgabe angezeigten zu öffnen.
Philᵀᴹ

Antworten:

7

Ja, dies ist Bug 2391334, der schon lange existiert und wahrscheinlich in naher Zukunft nicht behoben wird.

Eine Möglichkeit, dies zu umgehen, besteht darin, den Pfad für Skripte zu "kennen", ohne diesen Pfad tatsächlich fest zu codieren. Um dies in SQLPlus zu tun, ist ein Trick erforderlich. Wenn Sie versuchen, eine nicht vorhandene Datei auszuführen, wird eine Fehlermeldung mit dem Pfadnamen angezeigt.

Hier ist eine Demo davon in Aktion. Um Ihr Szenario nachzuahmen, habe ich:

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

Was wir tun können, ist, einige Befehle an der Vorderseite von call_script.sql hinzuzufügen, die den Pfad aufnehmen. Es sieht ein wenig seltsam aus, aber Sie sollten es nicht ändern müssen - es ist nur eine feste Sache, die Sie einfügen

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

Was hier passiert, ist, dass wir ein nicht existierendes Skript ausführen, das Folgendes zurückgibt:

"SP2-0310: Datei" Pfad \ _nonexistent_script.sql "kann nicht geöffnet werden

Mit ein wenig regulärem Ausdruck können wir den Pfad extrahieren, in einer SQLPlus-Variablen speichern und ab diesem Zeitpunkt verwenden.

Die endgültige Version Ihrer call_script.sql würde also so aussehen

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

und wenn wir das ausführen, erhalten wir Folgendes

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

und los geht's :-)

Connor McDonald
quelle