SQL * Plus, @ e caminhos relativos

9

De alguma forma, parece que o SQL * Plus (pelo menos no Windows) não consegue localizar um script com um caminho relativo quando chamado com @@e quando o caminho começa com um ponto simples ou duplo.

Por exemplo, em x:\some\whereTenho a seguinte estrutura de diretórios:

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

Ou seja: dois, script.sqlmas em locais diferentes.

O conteúdo de " script.sqlunder under" x:\some\whereé simplesmente

prompt SCRIPT root

enquanto o script.sqlconteúdo do outro é

prompt SCRIPT main-dir/main-subdir

call-script.sql

@@script.sql
@ script.sql

resultado esperado

Se eu iniciar o SQL * Plus x:\some\wheree depois fizer um

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

A saída será

SCRIPT main-dir/main-subdir
SCRIPT root 

Isso é esperado, já que o single @deve procurar caminhos a partir de onde o SQL * Plus foi iniciado e @@deve procurar caminhos no diretório do script que o contém.

saída inesperada

Agora , se eu mudar call-scripts.sqlassim:

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

o duplo @@parece mudar seu comportamento, na medida em que pesquisa caminhos de onde o SQL * Plus foi iniciado, e a saída será agora

SCRIPT root
SCRIPT root

o que não é o que eu esperava.


Esse comportamento está documentado em algum lugar e, mais importante, como preciso alterar call-scripts.sqlpara que ele chame caminhos relativos ( @@../../other-dir/other-sub-dir/script) corretamente?

René Nyffenegger
fonte
Qual é a sua variável de ambiente SQLPATH definida? Isso afeta quais diretórios são pesquisados.
Philᵀᴹ
Mesmo comportamento no Linux, FWIW. (E um "e" comercial é &, não @; o que não parece ter um nome real ). Parece ser um bug, pois é inconsistente. A única coisa que vem à mente é definir uma variável no script de nível superior com o caminho completo e fazer tudo com base nisso, mas isso não é muito conveniente, a menos que a estrutura de diretórios abaixo seja corrigida.
Alex Poole
Obrigado por apontar a coisa @ vs e comercial ... Eu deveria saber, mas quando escrevi o post, não prestei muita atenção. Agora está corrigido no título.
René Nyffenegger
2
Acabei de atacar o sqlplus com strace. Aqui estão as chamadas relevantes: pastebin.com/cVK1QQu4 Observe que ele não tentou stat nem acessou os arquivos "script.sql" em outros diretórios antes de tentar abrir os vistos na saída do pastebin.
Philᵀᴹ

Respostas:

7

Sim, esse é o bug 2391334, que existe há muito tempo e provavelmente não será corrigido em um futuro próximo.

Uma maneira de contornar isso é "conhecer" o caminho para scripts sem realmente codificá-lo. Para fazer isso no SQLPlus, é necessário um truque - se você tentar executar um arquivo inexistente, receberá uma mensagem de erro que inclui o nome do caminho.

Então, aqui está uma demonstração disso em ação. Para imitar seu cenário, eu tenho:

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

O que podemos fazer é adicionar alguns comandos à frente do call_script.sql, que escolherão o caminho. Parece um pouco estranho, mas você não precisa alterá-lo - é apenas uma coisa fixa em que você cola

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

O que está acontecendo aqui é que estamos executando um script inexistente, que retorna:

"SP2-0310: Não foi possível abrir o arquivo" path \ _nonexistent_script.sql "

portanto, com um pouco de regexp, podemos extrair o caminho, armazená-lo em uma variável SQLPlus e usá-lo a partir desse ponto.

Portanto, a versão final do seu call_script.sql ficaria assim

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 executamos isso, obtemos o seguinte

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

e lá vai você :-)

Connor McDonald
fonte