SQLPlus is trying to drop package twice - sql

While executing scripts in SQLPlus I've encountered a problem:
script.sql contains the following lines
#some_pkg.pks
#some_pkg.pkb
drop package some_pkg;
/
After calling
> sqlplus user/password#dbname #script.sql
the following messages are in console:
Package created.
Package body created.
Package dropped.
drop package some_pkg;
*
ERROR at line 1:
ORA-04043: object SOME_PKG does not exist
Please, explain what's happening here. Looks like the package is being dropped twice. Is it possible to avoid the error?

The rules of SQLplus command execution basically are:
Execute the current text when you encounter a semi-colon. Thus if a line doesn't end with a semi-colon, the current text continues to be collected.
If you encounter DECLARE or BEGIN, collect all the text and do not execute on semi-colons
If you encounter a slash (/), execute the collected text.
So what happens in your cases is, that both the semi-colon and the slash execute the DROP statements.
To fix it, remove the slash.
You only need the slash if you have a block of PL/SQL, which always with an END statement. Use semicolons for everything else.
Note: the above rules are simplified. It's more complex in practice.

Some examples will help to understand rules:
Below code will be executed once
begin
dbms_output.put_line('executed');
end;
/
Below code will not execute (missing semicolon)
begin
dbms_output.put_line('executed')
end
/
Below code will be executed twice
begin
dbms_output.put_line('executed');
end;
/
/
Below code will be executed once
select 1 from dual
/
Below code will be executed once
select 1 from dual;
Below code will be executed twice
select 1 from dual;
/

Related

TIBScript and local variables

I am working with Delphi 7 and Firebird 2.0. In my application I am using TIBScript components. The problem arises when I use local variables in the script. Firebird requires the names of local variables to be preceded by a colon in some cases. That’s where the problem lies in. The application stops showing the error message:
Dynamic SQL Error
SQL error code = -104
Token unknown - line 4, column 66
?
The token in question is the colon. Here is how my script looks like:
SET TERM ^ ;
EXECUTE BLOCK AS
DECLARE test_variable INT;
BEGIN
SELECT tt.id FROM test_table tt WHERE tt.name LIKE 'abc%' INTO :test_variable;
INSERT INTO test_table2(id, test_column)
VALUES(1, :test_variable);
INSERT INTO test_table3(id, test_column)
VALUES(1, :test_variable);
...
END^
SET TERM ; ^
The same script executes without any errors when run from IBExpert.
How can I use local variables in a TIBScript? Any help would be appreciated!
I want to add that this problem occurs only with variables inside an EXECUTE BLOCK construct. There is no problem with local variables in stored procedure and trigger definitions.
After executing the method TIBSQL.PreprocessSQL (Unit IBX.IBSQL line 2362), parameters marked with ":" on the front are replaced by "?". So you should use parameters without ":". Also I think it should be removed SET TERM. Instead, to set terminator value use the IBScript.Terminator property.
P.S. I watched unit IBX.IBSQL in Delphi 10.3 Rio.
this
EXECUTE BLOCK AS
DECLARE test_variable INT;
BEGIN
SELECT tt.id FROM USERS tt WHERE (tt.fname LIKE 'abc%') INTO test_variable;
END;
is executed properly when
IBScript.Terminator = ^;
Edit:
You can't execute INSERT with parameters in EXECUTE BLOCK using TIBScript component.
As Mark Rotteveel comented:
Unfortunately removing the colon is only an option in the into clause
in not with other occurrences of local variables or parameters.

Oracle SQLPlus: Echo without line numbers?

I'm working on a solution where several SQL and PL/SQL scripts are being run together, in a batch of sorts, via SQL*Plus.
I'm declaring SET ECHO OFF; and SET ECHO ON; at relevant points in the scripts so as to output relevant code.
Currently the output looks something like this:
SQL> DECLARE
2 ct number := 0;
3 ctChanges number := 0;
4
5 BEGIN
6 select count(*) into ct from ...
7 (...rest of code block...)
"some specific status message"
Commit executed.
We keep this output as a run-log in our build-environment, but can also access it as a plain text file.
One downside of this format however, is that if I'd like to copy a certain section of the code and run it again in an IDE (like Toad or SQL Developer), it's hard to exclude the line numbers.
Is it possible to tell SQL*Plus to output the code as above, but without including the line numbers?
You can use options sqlnumber and sqlprompt:
set sqlprompt ''
set sqlnumber off
SET SQLN[UMBER] {ON|OFF}
SET SQLNUMBER is not supported in iSQL*Plus
Sets the prompt for the second and subsequent lines of a SQL command or PL/SQL block. ON sets the prompt to be the line number. OFF sets the prompt to the value of SQLPROMPT.

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.

How do we print characters line by line and save it to csv or text file in PLSQL

DECLARE
V_NUMBER NUMBER :=23;
BEGIN
LOOP
V_NUMBER:=V_NUMBER+1;
EXIT WHEN V_NUMBER:=25;
--Some kind of function to be applied for printing and nesting lines into CSV or TEXT file.
END LOOP;
COMMIT;
END;
Scripting an Oracle SQL Query for Creating a CSV or Text Typed File Output
Consider running this from a SQL Plus session and use the SPOOL command. All output of the SQL command that follows will be written to the file name you specify.
If you need to append your results each successive time the SQL commands are run, then an OS level command would work appropriately when invoking this sqlplus executable block of PL/SQL:
Where the file name of this script is: "sample_csv_out.sql"
DECLARE
v_total_columns constant number:= 3; -- Number of columns queried
v_column_counter number;
v_csv_record varchar2(1000);
c_csv_column_format constant varchar2(15):=
'<<COLUMN1_VAL>>,<<COLUMN2_VAL>>,<<COLUMN3_VAL>>';
cursor result_cur is
SELECT column1, column2, column3
FROM tablea
WHERE column1 = ... ;
BEGIN
v_csv_record:= 'COLUMN1,COLUMN2,COLUMN3';
dbms_output.put_line (v_csv_record);
FOR i in result_cur LOOP
v_csv_record:= replace(c_csv_column_format, '<<COLUMN1_VAL>>', i.column1);
v_csv_record:= replace(v_csv_record, '<<COLUMN2_VAL>>', i.column2);
v_csv_record:= replace(c_csv_record, '<<COLUMN3_VAL>>', i.column3);
dbms_output.put_line(v_csv_record);
END LOOP;
END;
So, for example in a WINDOWS O/S environment, the call to append the output to a specific file name would be:
C:\> sqlplus sample_csv_out.sql >> mycsv_out.csv
The >> notation instructs the operating system to pipe the output of running sample_csv_out.sql via a sqlplus session.
The command DBMS_OUTPUT does the rest. If you need more details, see more Oracle documentation on DBMS_OUTPUT.
COMMENTS: I chose the RECORD STRING TEMPLATE approach to make this script a little more flexible and reusable. I recommend to keep any data manipulation logic within the CURSOR statement. Often when the two are mixed, it gets harder to debug any typos in syntax within a long string of values.
The construction of an output record was also designed to reduce typos, mistakes and frustration... if there are more than 3 columns in your own scripts, adding another element to the output string is mostly a cut-and-paste operation. Likewise with the "header" row (column titles).
You can read and write files in PL/SQL using the UTIL_FILE package
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/u_file.htm

How does "if xx > 0then" execute but not compile?

I've got a PL/SQL-Block which looks like this:
declare
L_Count number := 10;
begin
if L_Count > 0then
dbms_output.put_line('l_Count > 0');
else
dbms_output.put_line('l_Count <= 0');
end if;
exception
when others then
dbms_output.put_line('exception occurred');
end;
Note the fourth line containing 0then instead of 0 then.
Using PL/SQL-Developer, I can execute this block as an SQL statement, which actually outputs l_Count > 0. Using a "Program Window" and compiling this, PL/SQL-Developer says the following error:
Unable to perform operation due to errors in source code
How can this statement execute but not compile?
Thank you for your hints!
The behavior is not what I would expect either. However, both the PL/SQL Developer SQL Window and Command Window modes execute this consistently with how SQL*Plus behaves. So, this is either:
Not a bug, or
An Oracle bug but not an Allround Automations bug.
Execution and compilation are two separate things. The code block is an anonynous block and it cannot be compiled. However you can execute the block. Execution would show you l_Count > 0.
Thanks,
Aditya