SQL * Plus, @ e percorsi relativi


9

In qualche modo, sembra che SQL * Plus (almeno su Windows) non sia in grado di individuare uno script con un percorso relativo quando viene chiamato con @@e quando il percorso inizia con un punto singolo o doppio.

Ad esempio, in x:\some\whereHo la seguente struttura di directory:

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

Cioè: due script.sqlma in posizioni diverse.

Il contenuto di script.sqljust under x:\some\whereè semplicemente

prompt SCRIPT root

mentre il script.sqlcontenuto dell'altro è

prompt SCRIPT main-dir/main-subdir

call-script.sql legge

@@script.sql
@ script.sql

uscita prevista

Se avvio SQL * Plus da x:\some\wheree quindi faccio un

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

L'output sarà

SCRIPT main-dir/main-subdir
SCRIPT root 

Questo è previsto, dal momento che il singolo @dovrebbe cercare percorsi da dove è stato avviato SQL * Plus e @@dovrebbe cercare percorsi dalla directory dello script contenente.

uscita imprevista

Ora , se cambio call-scripts.sqlcosì:

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

il doppio @@sembra cambiare il suo comportamento, in quanto cerca percorsi da dove è stato avviato SQL * Plus e l'output sarà ora

SCRIPT root
SCRIPT root

che non è quello che mi aspettavo.


Questo comportamento è documentato da qualche parte e, cosa più importante, come devo cambiare in call-scripts.sqlmodo da chiamare @@../../other-dir/other-sub-dir/scriptcorrettamente i percorsi relativi ( )?


Qual è la variabile di ambiente SQLPATH impostata su? Ciò influenza quali directory vengono cercate.
Philᵀᴹ


Stesso comportamento su Linux, FWIW. (E una e commerciale è &, non @; che non sembra avere un vero nome ). Sembra essere un bug, poiché è incoerente. L'unica cosa che viene in mente è di impostare una variabile come script di livello superiore con il percorso completo e fare tutto in base a quello, ma ciò non è molto conveniente a meno che la struttura della directory sottostante non sia corretta.
Alex Poole,

Grazie per aver sottolineato la cosa @ e commerciale ... avrei dovuto saperlo, ma quando ho scritto il post non ho prestato molta attenzione. Ora è stato corretto nel titolo.
René Nyffenegger

2
Ho appena attaccato sqlplus con strace. Ecco le chiamate pertinenti: pastebin.com/cVK1QQu4 Si noti che non ha tentato di stat o accedere ai file "script.sql" in altre directory prima di tentare di aprire quelli visualizzati nell'output di pastebin.
Philᵀᴹ

Risposte:


7

Sì, questo è il bug 2391334 che esiste da molto tempo e probabilmente non verrà risolto nel prossimo futuro.

Un modo per aggirare questo problema è "conoscere" il percorso degli script senza realmente codificarlo. Per fare ciò in SQLPlus è necessario un trucco: se si tenta di eseguire un file inesistente, verrà visualizzato un messaggio di errore che include il nome del percorso.

Quindi ecco una demo di questo in azione. Per imitare il tuo scenario ho:

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

Quello che possiamo fare è aggiungere alcuni comandi all'inizio di call_script.sql che prenderà il percorso. Sembra un po 'strano, ma non dovresti cambiarlo - è solo una cosa fissa in cui incollare

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

Quello che sta succedendo qui, è che stiamo eseguendo uno script inesistente, che restituisce:

"SP2-0310: impossibile aprire il file" path \ _nonexistent_script.sql "

quindi con un po 'di regexp possiamo estrarre il percorso, memorizzarlo in una variabile SQLPlus e usarlo da quel momento in poi.

Quindi la versione finale del tuo call_script.sql sarebbe simile a questa

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

e quando lo eseguiamo, otteniamo quanto segue

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

e il gioco è fatto :-)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.