patternMinor
SQL*Plus, @, and relative paths
Viewed 0 times
sqlpathsplusandrelative
Problem
Somehow, it seems that SQL*Plus (at least on Windows) is unable to locate a script with a relative path when called with
For example, under
That is: two
The content of
while the other
expected output
If I start SQL*Plus from
The output will be
This is expected, since the single
unexpected output
Now, if I change
the double
which is not what I expected.
Is this behaviour documented somewhere, and more importantly, how do I have to change
@@ and when the path starts with a single or double dot.For example, under
x:\some\where I have the following directory structure:script.sql
main-dir\main-sub-dir
call-script.sql
script.sqlThat is: two
script.sql but at different locations. The content of
script.sql just under x:\some\where is simply prompt SCRIPT rootwhile the other
script.sql's content isprompt SCRIPT main-dir/main-subdircall-script.sql reads@@script.sql
@ script.sqlexpected output
If I start SQL*Plus from
x:\some\where and then do a@main-dir/main-sub-dir/call-scriptsThe output will be
SCRIPT main-dir/main-subdir
SCRIPT rootThis is expected, since the single
@ is supposed to search paths from where SQL*Plus was started and @@ is supposed to search paths from the containing script's directory.unexpected output
Now, if I change
call-scripts.sql so:@@./script.sql
@ ./script.sqlthe double
@@ seems to change it's behaviour, in that it searches paths from where SQL*Plus was started, and the output will now beSCRIPT root
SCRIPT rootwhich is not what I expected.
Is this behaviour documented somewhere, and more importantly, how do I have to change
call-scripts.sql so that it calls relative paths (@@../../other-dir/other-sub-dir/script) correctly?Solution
Yup, this is Bug 2391334 which has been around for long time, and probably will not be fixed in the near future.
One way of working around this is "know" the path for scripts without actually hard coding that path. To do this in SQLPlus requires a trick - if you try to run a non-existent file, then you'll get an error message that includes the path name.
So here's a demo of that in action. To mimic your scenario I've got:
What we can do is add some commands to the front of call_script.sql which will pick up the path. It looks a little odd, but you should not need to change it - its just a fixed thing you paste in
What's happening here, is we're running a non-existent script, which returns:
"SP2-0310: unable to open file "path\_nonexistent_script.sql"
so with a little regexp we can extract the path, store it in a SQLPlus variable and then use from that point on.
So the final version of your call_script.sql would look like this
and when we run that, we get the following
and there you go :-)
One way of working around this is "know" the path for scripts without actually hard coding that path. To do this in SQLPlus requires a trick - if you try to run a non-existent file, then you'll get an error message that includes the path name.
So here's a demo of that in action. To mimic your scenario I've got:
c:\temp\demo
script.sql
maindir
subdir
call_script.sql
script.sqlWhat we can do is add some commands to the front of call_script.sql which will pick up the path. It looks a little odd, but you should not need to change it - its just a fixed thing you paste in
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 onWhat's happening here, is we're running a non-existent script, which returns:
"SP2-0310: unable to open file "path\_nonexistent_script.sql"
so with a little regexp we can extract the path, store it in a SQLPlus variable and then use from that point on.
So the final version of your call_script.sql would look like this
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.sqland when we run that, we get the following
SQL> @maindir\mainsubdir\call_script
path was maindir\mainsubdir
script in subdir
script in subdirand there you go :-)
Code Snippets
c:\temp\demo
script.sql
maindir
subdir
call_script.sql
script.sqlset 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 onset 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.sqlSQL> @maindir\mainsubdir\call_script
path was maindir\mainsubdir
script in subdir
script in subdirContext
StackExchange Database Administrators Q#17347, answer score: 8
Revisions (0)
No revisions yet.