Use oracle SET values in PL/SQL - oracle

I was requested to set some environment parameters to migration files. However, such parameters as SQLBLANKLINES for instance, are only valid in sqlplus, other tools (e.g. Flyway) would be broken by its usage. Same is for autocommit.
Is there any way to perform following:
declare
v1 varchar2(60)
begin
v1 := SHOW SQLBLANKLINES
if (v1 is not empty) then
SET SQLBLANKLINES ON
end if;
end;
/
Or somehow query environment for available parameters to set?
Or somehow determine that exactly sqlplus is being used?
I'm aware of SHOW and SET commands, but I don't know how to place their results to variable and call SET inside PL/SQL.
Oracle is 11g.

You can't reference SQL*Plus commands in PL/SQL, as PL/SQL doesn't recognise them. Moreover, you can't use conditional statements directly in a SQL*Plus script, so you have to get a bit creative. You can, however, have a script that creates and runs another script, which you can use to inject conditional statements.
For example, this is a script that I use to either let my release script continue or not (it exits SQL*Plus):
continue_or_exit.sql:
prompt Do you want to continue script execution?
accept yn prompt 'Y / N : ';
set termout off;
set verify off;
set heading off;
set pause off;
set echo off;
column aaaa newline;
spool continue_or_exit_output.sql
select decode(upper('&&yn'), 'Y', 'prompt Executing ...',
'prompt Stopped'
),
decode(upper('&&yn'), 'Y', '', 'accept return_key prompt ''Press <Return>''') aaaa,
decode(upper('&&yn'), 'Y', '', 'exit') aaaa
from dual;
spool off;
set termout on;
#continue_or_exit_output.sql
set termout on;
set verify on;
set heading on;
You ought to be able to amend that for your case to decide whether to print out the relevant SQL*plus commands or not.

You cannot call SQL*Plus, or any client, commands from within PL/SQL. It is executed entirely on the server. You can tell which client is being used, at least if the client is well-behaved, but that doesn't really help you as you still can't use that information to control which client commands are issued.
The simplest approach may be to write a core script with the migration commands, and then a wrapper script for specific clients; so if you had core_migration.sql you could have another script called sqlplus_migration.sql that just did:
SET SQLBLANKLINES ON
-- any other SQL*Plus-specific set-up you want
SET PAGESIZE 0
SET LINESIZE 200
SET SERVEROUTPUT ON SIZE UNLIMITED
WHENEVER SQLERROR EXIT FAILURE
-- etc.
-- Run core migration script
#core_migration
exit 0;
SQL*Plus needs to be able to find the core script though, so it might be better/necessary to pass the full path to that with a substitution variable:
...
SET DEFINE ON
-- Run core migration script passed via command line
#&&1
exit 0;
... then call it as:
sqlplus -s -l usr/pwd #sqlplus_migration /path/to/core_migration.sql
(I don't like putting the credentials on the command line; your script could prompt for them instead but you suggested you wanted it to be non-interactive).
I'm not familiar with Flyway - it may just want to call the core script with no extra steps.

Related

not able to suppress sqlplus output on terminal

I am using following script to delimited file using spool in the unix server. I ssh into it using putty and execute the shell script.
Here is shell script:
/oracle/app/oracle/product/19.0.0/dbhome_1/bin/sqlplus -s /nolog<<-EOF
conn user/pass
SET PAGESIZE 0
SET LINESIZE 32000
SET NUMWIDTH 127
SET FEEDBACK OFF
set echo off
set heading off
set headsep off
SET MARKUP CSV ON DELIMITER | quote off
set termout off
spool mc_format.dat
select * from mytable;
spool off
EOF
but I am not able to suppress the rows printing out on the terminal, and eventually on log when I run using cron.
Is there any setting I am missing out?
Right from the documentation
SET TERMOUT OFF
Controls the display of output generated by commands in a script that is executed with #, ## or START. OFF suppresses the display so that you can spool output to a file without displaying the output on screen. ON displays the output on screen. TERMOUT OFF does not affect output from commands you enter interactively or redirect to SQL*Plus from the operating system.
So instead of the here document, call the script using one of the start methods mentioned.

Oracle SQL Script - Why spool creates file twice

I run the following SQL-script using Oracle SQL Developer. I don't know why it creates two spool file and it also displays the entire operations in the Oracle SQL Developer console which it should not. Maybe it is due to the SET FEEDBACK ON and SET FEEDBACK OFF for each delete statement.
It creates two files and displays everything in script-output only when there are some records for deletion.
The script's call
#"C:\RM.sql"
The script
SET PAGES 0
SET LINESIZE 10000
SET TRIMS ON
SET ECHO OFF
SET HEADING ON
SET VERIFY OFF
SET FEEDBACK OFF
SET TERMOUT OFF
SET SERVEROUTPUT on size 1000000
SET TIMING OFF
SET COLSEP '|'
alter session set NLS_DATE_FORMAT = 'dd.mm.yyyy hh24:mi:ss';
whenever oserror exit -1
whenever sqlerror exit -2
-- The current timestamps into 'times' variable
column times new_value times noprint
select to_char(sysdate, 'YYYYMMDD_HH24MISS') times from DUAL;
-- variables definition
define output_file="C:\temp\filename_&times..log"
-- echo some text to the standard output
SET TERMOUT ON
PROMPT
PROMPT "The script counts and reports the records to be deleted..."
PROMPT
SET TERMOUT OFF
-- write the results to the 'output_file' file
spool &output_file
PROMPT
PROMPT "BEGIN------------------------------"
PROMPT "delete from the_table1"
select 'Total records BEFORE delete: ' || count (*) as count_records from the_table1;
SET FEEDBACK ON
PROMPT "Actual deletion of records..."
delete from the_table1;
commit;
SET FEEDBACK OFF
PROMPT "END------------------------------"
PROMPT
PROMPT "BEGIN------------------------------"
PROMPT "delete from the_table2"
select 'Total records BEFORE delete: ' || count (*) as count_records from the_table2;
SET FEEDBACK ON
PROMPT "Actual deletion of records..."
delete from the_table2;
commit;
SET FEEDBACK OFF
PROMPT "END------------------------------"
PROMPT
PROMPT "The script completed..."
SPOOL OFF
SET TERMOUT ON
PROMPT
PROMPT "&output_file has been successfully ended."
PROMPT
PROMPT
EXIT
;
I seem to recall TERMOUT and ECHO options depend on how sqlplus is being run and can give different results, similar to what you are seeing.
I'm using sqlplus as a example of how interactions with the run environment can affect output. This isn't really an answer, and I cannot reproduce the scenarios I used to see often, but I hope the following perhaps will offer some pointers as to what might be encountered.
Start with a simple test script test_off.sql:
set echo off
set termout off
prompt text1
spool f1.txt
prompt text2
spool off
prompt text 3
quit
Now let's run it a number of different ways:
1 Non-interactively Parameterised
$ sqlplus -S un/pw#idb #test_off.sql
$ cat f1.txt
text2
No output to screen, spool file created, with only the spooled contents.
2. Interactively
$ sqlplus -S un/pw/#db
#test_off.sql
$ cat f1.txt
text2
No output to screen, spool file created, with only the spooled contents.
3. Run as piped feed
$ cat test_off.sql | sqlplus -S un/pw#db
text1
text2
text 3
Here we see all the PROMPT command results on screen.
Similar effects may be seen if run within a HEREDOC block.
I've definitely seen (in older versions) some strange inconsistencies and perhaps your SQL Developer is similarly afflicted.

Run a program within a batch file

I need to make a batch file which will execute a series of commands within a program. I need it to connect to an oracle database and then initiate a pull.
Here is by current file:
sqlplus [username]/[pass]#[host]:[port]/[service]
set feedback off
set term off
set linesize 32000
set pagesize 0
set trimspool on
set underline off
set heading on
set newpage none
spool C:\1.csv CREATE
[Query Goes here]
I run the script, but it doesn't execute anything except the first line. It connects okay, but waits for me to quit sqlplus to execute the rest of the script. Is there a way to fix this? If possible I would like to avoid using multiple files.
If anyone comes across this question looking for a *nix based solution, it'd be something like this:
sqlplus -s <username>/password <<EOF
set feedback off
set term off
set linesize 32000
set pagesize 0
set trimspool on
set underline off
set heading on
set newpage none
spool C:\1.csv CREATE
EOF
The subsequent commands are sent to SQLPLUS until it encounters EOF, then SQLPLUS will close.
But I'm not sure how to do the equivalent on Windows.

pass sqlplus value to shell variable

the below picture shows what gets returned when I run sqlplus in shell
but when I run this from the "run" command:
powershell.exe -noexit c:\sqltriggers\voicetrigger2.ps1
with voicetrigger2.ps1 as this:
$(sqlplus user/pass#OMP1 '#C:\sqltriggers\VOICEBLOCKTRIG.SQL');
I get this:
I should expect a 3 back. The issue is, I try to set that as a variable, and if the integer is greater than zero, run a BAT file. But I don't think the SQLPlus is returning JUST an integer value. I think its actually returning this:
count(*)
3
How do I get it to just return the integer value from the SQLplus command?
SQL*Plus isn't returning anything, it's displaying the result of the query on standard output. To get the direct call to only show 3 you can set heading off in the SQL script, and also call SQL*Plus with the -s flag to suppress the banner. You probably also want an exit at the end of the SQL script so it doesn't stay sitting at the SQL> prompt.
The same applies to the powershell call, but there's something else going on there; the 17 is a line number which means it's waiting for more input and hasn't executed the commands in the SQL script, which suggests either a query without a terminating ; or /, or a PL/SQL block without a terminating /. But if it's exactly the same SQL you ran in the first example then that is a bit odd as they should behave the same. You should add the SQL script contents to the question to see what might be wrong.
The only thing I can think of that would change behaviour like that is if you had a login.sql that includes a set sqlterminator command, but you'd have to be picking up different login.sql files from the two calls... which is plausible if powershell has its own environment variables, perhaps.
It won't work this way. As Alex mentioned, sqlplus doesn't return anything as a function - it only writes whatever output you generate to standard output.
You can have variables in sqlplus, but there is no easy way to pass them to host environment. The only way I can think of is to use spool command to generate another batch file, which will actually set your host variables, and then process them the way you want in your host script.
Something like this:
16:30:20 SYSTEM#sandbox> get host.sql
1 SET VERIFY OFF TRIMSPOOL ON TERMOUT OFF HEADING OFF LINESIZE 4000 PAGES 0 FEEDBACK OFF timing off
2 spool s:\.tmp\host.ps1
3 select '$env:MY_VAR="'||dummy||'"' from dual;
4 spool off
5* exit
16:30:25 SYSTEM#sandbox> #host.sql
Disconnected from Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production
PS S:\.tmp> cat host.ps1
$env:MY_VAR="X"
PS S:\.tmp> .\host.ps1
PS S:\.tmp> $env:my_var
X
PS S:\.tmp>
sqlplus -s /nolog <<EOF > query_result.txt
set heading off feedback off pagesize 0 linesize 30000 trimout on ;
select 5 from dual;
exit;
EOF
for i in `cat query_result.txt `
do
exit $i
done
try adding SET HEADING OFF in the beginning of your file. Check this answer (check the second best voted answer)

Can I stop SQL*Plus from displaying "connected" when I have a "connect" in a script?

I have a few sql scripts that I need to run via SQL*Plus. These
scripts connect several times as different users with a connect user_01/pass_01#db_01. Now, each time the script does such a connect, it confirms the successful connection with a connected. This is distracting and I want to turn it off.
I can achieve what I want with a
set termout off
connect user_01/pass_01#db_01
set termout on
Is there a more elegant solution to my problem?
Note, it doesn't help to permanently set termout off at the start of the script since I need to know if a command didn't run successfully.
Here's a tip I've used from Tom Kyte's book (forget which one). I have a script called connect.sql in my sqlplus directory:
set termout off
connect &1
#login
and in my glogin.sql I've added this:
select lower(user) || '#' ||
substr( global_name,1, decode( dot, 0, length(global_name), dot-1) )
global_name
from (select global_name, instr(global_name,'.') dot from global_name );
set sqlprompt '&gname> '
set termout on
then I call
#connect user_01/pass_01#db_01
instead of
connect user_01/pass_01#db_01
If it really bothers you you could try
SQL> set feedback off
SQL> alter session set current_schema=SCOTT;
But this may not meet your needs ....

Resources