SQL * Plus, @, dan jalur relatif

9

Entah bagaimana, tampaknya SQL * Plus (setidaknya pada Windows) tidak dapat menemukan skrip dengan path relatif ketika dipanggil dengan @@dan ketika path dimulai dengan satu atau dua titik.

Misalnya, di bawah x:\some\wheresaya memiliki struktur direktori berikut:

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

Yaitu: dua script.sqltetapi di lokasi yang berbeda.

Isi script.sqlhanya di bawah x:\some\whereini sederhana

prompt SCRIPT root

sementara script.sqlkonten lainnya adalah

prompt SCRIPT main-dir/main-subdir

call-script.sql membaca

@@script.sql
@ script.sql

output yang diharapkan

Jika saya memulai SQL * Plus dari x:\some\wheredan kemudian lakukan a

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

Outputnya adalah

SCRIPT main-dir/main-subdir
SCRIPT root 

Ini diharapkan, karena single @seharusnya mencari jalur dari mana SQL * Plus dimulai dan @@seharusnya mencari jalur dari direktori skrip yang berisi.

hasil yang tak terduga

Sekarang , jika saya mengubahnya call-scripts.sql:

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

ganda @@tampaknya mengubah perilaku itu, karena mencari jalan dari mana SQL * Plus dimulai, dan output sekarang akan menjadi

SCRIPT root
SCRIPT root

yang bukan itu yang saya harapkan.


Apakah perilaku ini didokumentasikan di suatu tempat, dan yang lebih penting, bagaimana saya harus berubah call-scripts.sqlsehingga ia memanggil jalur relatif ( @@../../other-dir/other-sub-dir/script) dengan benar?

René Nyffenegger
sumber
Untuk apa variabel lingkungan SQLPATH Anda atur? Itu mempengaruhi direktori mana yang dicari.
Philᵀᴹ
Perilaku yang sama di Linux, FWIW. (Dan ampersand adalah &, bukan @; yang tampaknya tidak memiliki nama asli ). Tampaknya menjadi bug, karena itu tidak konsisten. Satu-satunya hal yang terlintas dalam pikiran adalah untuk menetapkan variabel itu script tingkat atas dengan path lengkap dan melakukan semuanya berdasarkan itu, tapi itu tidak terlalu nyaman kecuali struktur direktori di bawah yang diperbaiki.
Alex Poole
Terima kasih telah menunjukkan hal @ vs ampersands ... Saya seharusnya tahu, tapi ketika saya menulis posting saya tidak begitu memperhatikan. Sekarang sudah diperbaiki dalam judul.
René Nyffenegger
2
Saya baru saja menyerang sqlplus dengan strace. Inilah panggilan-panggilan yang relevan: pastebin.com/cVK1QQu4 Perhatikan bahwa ia tidak mencoba untuk membuat stat atau mengakses file "script.sql" di direktori lain sebelum mencoba untuk membuka yang terlihat di output pastebin.
Philᵀᴹ

Jawaban:

7

Yup, ini Bug 2391334 yang telah ada sejak lama, dan mungkin tidak akan diperbaiki dalam waktu dekat.

Salah satu cara untuk mengatasi ini adalah "tahu" jalan untuk skrip tanpa benar - benar sulit mengkodekan jalur itu. Untuk melakukan ini dalam SQLPlus membutuhkan trik - jika Anda mencoba menjalankan file yang tidak ada, maka Anda akan mendapatkan pesan kesalahan yang menyertakan nama path.

Jadi, inilah demo dari tindakan itu. Untuk meniru skenario Anda, saya punya:

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

Yang bisa kita lakukan adalah menambahkan beberapa perintah ke bagian depan call_script.sql yang akan mengambil path. Ini terlihat sedikit aneh, tetapi Anda tidak perlu mengubahnya - itu hanya hal yang Anda tempelkan

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

Apa yang terjadi di sini, adalah kami menjalankan skrip yang tidak ada, yang mengembalikan:

"SP2-0310: tidak dapat membuka file" path \ _nonexistent_script.sql "

jadi dengan regexp kecil kita dapat mengekstrak path, menyimpannya dalam variabel SQLPlus dan kemudian menggunakannya sejak saat itu.

Jadi versi terakhir dari call_script.sql Anda akan terlihat seperti ini

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

dan ketika kita menjalankannya, kita mendapatkan yang berikut

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

dan di sana Anda pergi :-)

Connor McDonald
sumber