SQL * Plus, @ et chemins d'accès relatifs


9

D'une certaine manière, il semble que SQL * Plus (au moins sous Windows) ne parvienne pas à localiser un script avec un chemin d'accès relatif lorsqu'il est appelé avec @@et lorsque le chemin d'accès commence par un point simple ou double.

Par exemple, sous x:\some\whereJ'ai la structure de répertoires suivante:

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

C'est-à-dire: deux script.sqlmais à des endroits différents.

Le contenu d'un script.sqlpeu moins x:\some\whereest simplement

prompt SCRIPT root

tandis que le script.sqlcontenu de l'autre est

prompt SCRIPT main-dir/main-subdir

call-script.sql lit

@@script.sql
@ script.sql

production attendue

Si je démarre SQL * Plus à partir de x:\some\where, puis fais un

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

La sortie sera

SCRIPT main-dir/main-subdir
SCRIPT root 

Cela est attendu, car le single @est censé rechercher des chemins à partir de l'endroit où SQL * Plus a été démarré et @@est censé rechercher des chemins à partir du répertoire du script contenant.

sortie inattendue

Maintenant , si je change call-scripts.sqlainsi:

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

le double @@semble changer son comportement, en ce sens qu'il recherche les chemins d'où SQL * Plus a été démarré, et la sortie sera désormais

SCRIPT root
SCRIPT root

ce qui n'est pas ce que j'attendais.


Ce comportement est-il documenté quelque part et, plus important encore, comment dois-je changer call-scripts.sqlpour qu'il appelle @@../../other-dir/other-sub-dir/scriptcorrectement les chemins relatifs ( )?


À quoi votre variable d'environnement SQLPATH est-elle définie? Cela affecte les répertoires recherchés.
Philᵀᴹ


Même comportement sous Linux, FWIW. (Et une esperluette est &, pas @; qui ne semble pas avoir un vrai nom ). Semble être un bug, car il est incohérent. La seule chose qui me vient à l'esprit est de définir une variable dans le script de niveau supérieur avec le chemin complet et de tout faire en fonction de cela, mais ce n'est pas très pratique à moins que la structure de répertoire ci-dessous ne soit fixe.
Alex Poole

Merci d'avoir souligné la chose @ vs esperluette ... J'aurais dû le savoir, mais quand j'ai écrit le post, je n'y ai pas vraiment prêté attention. C'est maintenant corrigé dans le titre.
René Nyffenegger

2
Je viens d'attaquer sqlplus avec strace. Voici les appels pertinents: pastebin.com/cVK1QQu4 Notez qu'il n'a pas tenté de stat ou d'accéder aux fichiers "script.sql" dans d'autres répertoires avant d'essayer d'ouvrir ceux vus dans la sortie pastebin.
Philᵀᴹ

Réponses:


7

Oui, c'est le bug 2391334 qui existe depuis longtemps et qui ne sera probablement pas corrigé dans un avenir proche.

Une façon de contourner ce problème est de «connaître» le chemin des scripts sans réellement coder en dur ce chemin. Pour ce faire dans SQLPlus, il faut une astuce - si vous essayez d'exécuter un fichier inexistant, vous obtiendrez un message d'erreur qui inclut le nom du chemin.

Voici donc une démonstration de cela en action. Pour imiter votre scénario, j'ai:

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

Ce que nous pouvons faire, c'est ajouter quelques commandes à l'avant de call_script.sql qui reprendront le chemin. Cela semble un peu étrange, mais vous ne devriez pas avoir besoin de le changer - c'est juste une chose fixe que vous collez

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

Ce qui se passe ici, c'est que nous exécutons un script inexistant, qui renvoie:

"SP2-0310: impossible d'ouvrir le fichier" path \ _nonexistent_script.sql "

donc avec une petite expression régulière, nous pouvons extraire le chemin, le stocker dans une variable SQLPlus et ensuite l'utiliser à partir de ce moment.

Ainsi, la version finale de votre call_script.sql ressemblerait à ceci

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

et lorsque nous exécutons cela, nous obtenons ce qui suit

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

et voilà :-)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.