sqlplus variable value is not accepting in EOF block in shell - sql

I am unable to give input to the variable "y" written in below code. Can any one help us Please.
Code :
#!/bin/bash
${ORACLE_HOME}/bin/sqlplus -s abcd/passabcd <<EOF
declare
res varchar2(9) := '&y';
begin
insert into abc values(10);
if res in ('commit;')
then
EXECUTE IMMEDIATE 'commit;';
elsif res in ('rollback;')
then
EXECUTE IMMEDIATE 'rollback;';
else
DBMS_OUTPUT.PUT_LINE('Enter Correct Input');
end if;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error msg ' || substr(sqlerrm,1,200));
end;
/
EOF
if i run this, below is the screen. automatically i am getting sp2-0546 error without entering any input.
[oracle#ssmz861 ~]$ ./mm.sh
Enter value for y:SP2-0546: User requested Interrupt or EOF detected.
[oracle#ssmz861 ~]$
here is the scenario: I have a pl/sql code i need to give to sqlplus to execute in following manner like <EOF .....EOF. in that one i have to see the output of one query and decide whether need to commit or rollback by giving input.
thanks in advance
Siva

Related

How to reproduce ORA-01940: cannot drop a user that is currently connected through Jenkins pipeline?

Through Jenkins pipeline, if I get error ORA-01940: cannot drop a user that is currently connected, I want to perform some action.
FOr testing I should get that message. If I create user and log in with it to sql developer and try to drop it through pipeline it results into above error -
sh '''
sqlplus -s /nolog <<-EOF
connect system/system#orcl
DROP USER TEST_USER;
exit
EOF
'''
Is there any way I can connect using that user and drop it through pipeline so results into above error?
If you are running that part through a PIPELINE in Jenkins using shell script, there are some options:
Get a specific Return Code of the Operation
In this case, you might do the following
sh '''
sqlplus -s /nolog <<-EOF
connect system/system#orcl
whenever sqlerror exit 99
DROP USER TEST_USER;
exit
EOF
'''
This operation will return 99 in case you got the error. You must evaluate the the return of the operation using $?
Example
Session 1 ( as system )
SQL> create user test identified by Oracle_1 ;
User created.
SQL> grant connect to test ;
Grant succeeded.
I connect with the user test, and then with my system user I will try to drop it
SQL> whenever sqlerror exit 99
SQL> drop user test ;
drop user test
*
ERROR at line 1:
ORA-01940: cannot drop a user that is currently connected
Disconnected from Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64 bit Production
[ftpcpl#scglvdoracp0040 ~]$ echo $?
99
Using PLSQL Block to return code or message
However, if you want something different than the option before, like having the code displayed automatically without evaluation, then you can get the message display by the output using an anonymous PL/SQL block.
In your case, I would use something like this:
sh '''
sqlplus -s /nolog <<-EOF
connect system/system#orcl
set serveroutput on feedback off
declare
user_is_conn exception;
verror varchar2(100);
pragma exception_init ( user_is_conn , -1940 );
begin
execute immediate q'[ DROP USER TEST ]';
exception
when user_is_conn then
verror := sqlerrm ; -- the whole error message
-- verror := sqlcode ; -- only the code 1940
dbms_output.put_line(verror); -- message
when others then
raise;
end;
/
exit
EOF
'''
I commented verror := sqlcode in the section before to show the whole message. An example of this running in Linux would be:
$ $ORACLE_HOME/bin/sqlplus -S "/ as sysdba" << eof
set serveroutput on feedback off
declare
user_is_conn exception;
verror varchar2(100);
pragma exception_init ( user_is_conn , -1940 );
begin
execute immediate 'DROP USER TEST' ;
exception
when user_is_conn then
verror := sqlerrm ;
dbms_output.put_line(verror);
when others then
raise;
end;
/
eof
ORA-01940: cannot drop a user that is currently connected
Be aware that this PL/SQL block is ended OK. I mean, from OS perspective the operation return code is 0. If you want that as a error, you need to raise the error, but in that case the message would be different.

How to get user input in ORACLE using ACCEPT?

I need to get input from user in runtime in ORACLE. I am trying to do this.
Get input 'name' from user
Greet user with 'name' using DBMS_OUTPUT
My code so far:
ACCEPT name PROMPT 'Your name:'
declare
a varchar2(10);
begin
a := '&x';
end;
You need to use the name you assigned in the ACCEPT statement in your code. So
ACCEPT name PROMPT 'Your name:'
begin
dbms_output.put_line ('Hello &name !');
end;
/
Regarding your comment:
"ACCEPT name PROMPT 'Your name:' still is a unsuported command"
According to your comment you're using Oracle's LiveSQL, right? Well, accept is a SQL*Plus command for handling input parameters; SQL*Plus is part of a client install. LiveSQL is a different client. If you read its FAQs you will see:
Can I use input parameters?
No, we do not support input parameters at runtime.

Print DBMS_OUTPUT.PUT_LINE in a file with a bash script

I have a pl/SQL query that has a variable .
I want DBMS_OUTPUT.PUT_LINE to a file used on the machine (linux)
Does someone know how to do this?
You need to put some pieces together. Here is my inspiration: DBMS_OUTPUT.PUT_LINE not printing
a) put your plsql in an sql script, e.g. d.sql - the key here is set serveroutput:
set serveroutput on size 30000;
begin
DBMS_OUTPUT.PUT_LINE('my line');
end;
/
exit
b) Then write another script - ksh this time - containing:
sqlplus / #d.sql > output.txt
If you want to restrain what displays from sqlplus, then read appropriate documentation about set statement

How to capture the result of stored procedure through shell script?

I'm trying to execute stored procedure through shell script and try to get return from stored procedure but I didn't get any thing from the stored procedure on other hand same thing I do with sqlplus prompt and I'm able to get the result
sqlplus -silent xxx#xxx <<EOF
set serveroutput on
declare
DE_REC_COUNT number(10);
begin
DE_DUP_PROC ('T_MCL_30404_20150317_020','MCL','30404','FT',DE_REC_COUNT);
end;
EOF
Through sqlplus prompt
SQL> set serveroutput on
declare
DE_REC_COUNT number;
begin
DE_DUP_PROC ('T_MCL_30404_20150317_020','MCL','30404','FT',DE_REC_COUNT);
end;
0
PL/SQL procedure successfully completed.
The version of the anonymous block in the shell script will not be executed as shown, because you don't have a slash after the block to run it. If you run that you get no output at all. If you change it to have a slash:
sqlplus -silent xxx#xxx <<EOF
set serveroutput on
declare
DE_REC_COUNT number(10);
begin
DE_DUP_PROC ('T_MCL_30404_20150317_020','MCL','30404','FT',DE_REC_COUNT);
end;
/
EOF
then you'll see:
0
PL/SQL procedure successfully completed.
You've shown the interactive version in SQL*Plus without the slash too, but you must have had that to see the output you showed.
If you want the zero - which seems to be coming from a dbms_output call in your procedure, rather than directly from your anonymous block - n a shell variable you can refer to later, you can assign the output of the heredoc to a variable:
MY_VAR=`sqlplus -silent xxx#xxx <<EOF
set serveroutput on
set feedback off
declare
DE_REC_COUNT number(10);
begin
DE_DUP_PROC ('T_MCL_30404_20150317_020','MCL','30404','FT',DE_REC_COUNT);
end;
/
EOF`
printf "Got back MY_VAR as %s\n" ${MY_VAR}
Note that I've added set feedback off so you don't see the PL/SQL procedure successfully completed line. Now when you run that you'll see:
Got back MY_VAR as 0
and you can do whatever you need to with ${MY_VAR}. It depends what you mean by 'capture' though.
Here's an example of how it can be done by surrounding the code with the evaluation operators (` back quotes):
#!/bin/sh
results=`sqlplus -s xxx#xxx <<EOF
set serveroutput on feedback off
declare
DE_REC_COUNT number(10);
begin
DE_DUP_PROC ('T_MCL_30404_20150317_020','MCL','30404','FT',DE_REC_COUNT);
end;
/
EOF`
echo $results
Lets say for instance I have a below procedure which calculates the sum of two numbers and prints the total using dbms_output.put_line() method
CREATE OR REPLACE
PROCEDURE SUM
(
a IN NUMBER,
b IN NUMBER)
AS
total NUMBER;
BEGIN
total:= a + b;
dbms_output.put_line(total);
END;
Then in order to call this in our shell script we need to call this procedure in an anonymous block and store in a variable, later using echo we can execute the command.
plsqlcode=`sqlplus -silent hr/sandeep#orcl <<EOF
set serveroutput on
begin
sum(10,20);
end;
/
EOF`
echo $plsqlcode
Ideally this is not a recommended approach you should keep your shell and pl/sql code in separate files.

Cancel SQL *PLUS Execution without raising an error

i have a tricky SQL Problem:
We have a huge SQL Script which installs our application on the DB server.
We want to skip the database installation if the latest update didn't change anything in the DB.
I have implemented following check, which is executed before the other SQL commands:
check_current_version_delta.sql:
DECLARE
v_deploy_version VARCHAR2(30) := '&db_deploy_version';
v_check BOOLEAN := FALSE;
BEGIN
DBMS_OUTPUT.PUT_LINE( '--------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE( 'Check if we have a new DB version');
DBMS_OUTPUT.PUT_LINE( '--------------------------------------------------------------------------------');
FOR cu_version IN (SELECT version FROM &DB_CURRENT_USER..db_deployment WHERE version = v_deploy_version AND ROWNUM = 1) LOOP
v_check := TRUE;
END LOOP;
IF v_check THEN
RAISE_APPLICATION_ERROR( -20001, 'DB Version: '||v_deploy_version||' is already installed');
END IF;
END;
/
This is working very well but our installation team complains about the ORA-XXXXX Error in the log, because they have automated error checks this installation is marked as FAIL (though there was no actual error)
So now the actual problem:
I need to cancel the execution of the SQL without any errors in the LOG. Is this even possible?
Alternative would be to make the rest of the installation dependent on the outcome of the script above. But i'm not sure how to accomplish that.
Have you some suggestions on how to handle it the good way?
One possible way is to create three scripts: The first checks for the condition and either calls the second or the third. The second does the real job. The third is an empty dummy, to avoid the error message cause by calling a non-existent script
In code, it looks like this:
col SCRIPT1_COL new_val SCRIPT1
SELECT case
when version = '&db_deploy_version' then 'dummy.sql'
else 'upgrade_db.sql'
end as SCRIPT1_COL
FROM &DB_CURRENT_USER..db_deployment;
#&SCRIPT1
Alternatively, you could use the method shown above to load either a script "dummy.sql" that does nothing or a script "exit.sql" that just contains the exit command, and execute it before doing the real job.
Presumably you're already using whenever sqlerror so make it terminate when you raise that exception, and you're redirecting the output to your log file. If so you can just hide the text of the exception with set termout off:
whenever sqlerror exit success
set termout off
DECLARE
...
BEGIN
...
IF v_check THEN
RAISE_APPLICATION_ERROR( -20001,
'DB Version: '||v_deploy_version||' is already installed');
END IF;
END;
/
set termout on
whenever sqlerror exit failure
... the rest of your script
The script will stop if the exception is raised but produce no output. The success means anything that runs this won't decide it has errored independently of the log; the exit code from sqlplus will be zero.
You may be spooling to output instead; in which case just don't start the spool until after your check. Or if you have things before this that you do have to spool, turn the spool off and then on again afterwards with append.