Oracle dynamic sql, works everywhere but at customers - sql

I have a stored procedure which executes some dynamic sql, shown below. I've tried to cut it down as much as possible so ignore any little errors.
In the office it works, everytime, on 11.2, 10.2, 10.1. At the customers it fails with a message:
Unexpected Error
Error Message = "Msg:
MyProc
ORA-06550: line 1, column 1:
PLS-00103: Encountered the symbol "" when expecting one of the following:
begin case declare exit for function goto if loop mod null
If I capture the dynamic sql that the customer is generating and place it in a variable like below, running on work machines, it works, so it's not that dodgy sql is getting generated. Normally the sql comes from the client so here I've doubled the to_date quotes.
mySQL := '
declare
pADMINDATE DATE := :1;
pEMPLOYEEIDLIKE VARCHAR2(40) := :2;
pINCLUDEEMPLOYEE number := :3;
begin
BEGIN OTHERPROC.OTHERPROC (1,TO_DATE(''2012-10-03'', ''YYYY-MM-DD''),TO_DATE(''2012-10-03'', ''YYYY-MM-DD''),0);
END;
INSERT INTO TP_EMPLOYEES (
ID,
EMPLOYEECODE
)
SELECT ROWNUM,
EMPLOYEECODE
FROM (
SELECT EMPLOYEECODE
FROM (SELECT DISTINCT EMPLOYEECODE FROM TP_EEF_TEMP) DISTINCTEMPCODES) A;
end; ';
EXECUTE IMMEDIATE
mySQL
using
pADMINDATE,
pEMPLOYEEIDLIKE,
pINCLUDEEMPLOYEE;
It's not the database version that causes the problem, could it be permissions? It calls another stored procedure within itself which we do regularly in non dynamic sql, could it be that?
At a loss here
Thanks

I have found the "works in this server but doesn't work on that server" type of problems before.
Usually it's related to implicit date <-> varchar conversions: since different database servers can have different default formats, it's possible for a statement with an implicit conversion to work in one place and fail in another.
I suggest you to try running your example removing the pADMINDATE date variable.

It was carriage returns! Adding this line fixed the problem
pQUERY2 := REPLACE(pQUERY, chr(13));
A similar problem was highlighted here
https://forums.oracle.com/forums/thread.jspa?threadID=1117462
Thanks for the answers anyway, if anyone knows I would be interested in knowing what setting/patch/whatever makes Oracle sensitive to this, i.e. I tried this on 3 different versions of oracle including the one the customer was on, -but- I didn't patch my 10.2.1 version.
Is it something that is fixed in a patch? Is it a setting?

Related

How to use SET OPTION within a DB2 stored procedure

I read (and tried) that I cannot use WITH UR in DB2 stored procedures. I am told that I can use SET OPTION to achieve the same. However, when I implement it in my stored procedure, it fails to compile (I moved around its location same error). My questions are:
Can I really not use WITH UR after my SELECT statements within a procedure?
Why is my stored procedure failing to compile with the below error
message?
Here is a simplified version of my code:
CREATE OR REPLACE PROCEDURE MySchema.MySampleProcedure()
DYNAMIC RESULT SETS 1
LANGUAGE SQL
SET OPTION COMMIT=*CHG
BEGIN
DECLARE GLOBAL TEMPORARY TABLE TEMP_TABLE AS (
SELECT 'testValue' as "Col Name"
) WITH DATA
BEGIN
DECLARE exitCursor CURSOR WITH RETURN FOR
SELECT *
FROM SESSION.TEMP_TABLE;
OPEN exitCursor;
END;
END
#
Error Message:
SQL0104N An unexpected token "SET OPTION COMMIT=*CHG" was found
following " LANGUAGE SQL
Here is code/error when I use WITH UR
CREATE OR REPLACE PROCEDURE MySchema.MySampleProcedure()
LANGUAGE SQL
DYNAMIC RESULT SETS 1
--#SET TERMINATOR #
BEGIN
DECLARE GLOBAL TEMPORARY TABLE TEMP_TABLE AS (
SELECT UTI AS "Trade ID" FROM XYZ WITH UR
) WITH DATA;
BEGIN
DECLARE exitCursor CURSOR WITH RETURN FOR
SELECT *
FROM SESSION.TEMP_TABLE;
OPEN exitCursor;
END;
END
#
line 9 is where the DECLARE GLOBAL TEMPORARY ... is
DB21034E The command was processed as an SQL statement because it was
not a valid Command Line Processor command. During SQL processing it
returned: SQL0109N The statement or command was not processed because
the following clause is not supported in the context where it is
used: "WITH ISOLATION USE AND KEEP". LINE NUMBER=9. SQLSTATE=42601
Specifying the isolation level:
For static SQL:
If an isolation-clause is specified in the statement, the value of that clause is used.
If an isolation-clause is not specified in the statement, the isolation level that was specified for the package when the package was bound to the database is used.
You need to bind the routine package with UR, since your DECLARE GTT statement is static. Before CREATE OR REPLACE use the following in the same session:
CALL SET_ROUTINE_OPTS('ISOLATION UR')
P.S.: If you want to run your routine not only 1 time in the same session without an error, use additional WITH REPLACE option of DECLARE.
If your Db2 server runs on Linux/Unix/Windows (Db2-LUW), then there is no such statement as SET OPTION COMMIT=*CHG , and so Db2 will throw an exception for that invalid syntax.
It is important to only use the matching Db2 Knowledge Centre for your Db2 platform and your Db2-version. Don't use Db2-Z/OS documentation for Db2-LUW development. The syntax and functionalities differ per platform and per version.
A Db2-LUW SQL PL procedure can use with ur in its internal queries, and if you are getting an error then something else is wrong. You have to use with ur in the correct syntax however, i.e in a statement that supports this clause. For your example you get the error because the clause does not appear to be valid in the depicted context. You can achieve the desired result in other ways, one of them being to populate the table in a separate statement from the declaration (e.g insert into session.temp_table("Trade ID") select uti from xyz with ur; ) and other ways are also possible.
One reason to use the online Db2 Knowledge Cenbtre documentation is that it includes sample programs, including sample SQL PL procedures, which are also available in source code form in the sample directory of your DB2-LUW server, in addition to being available on github. It is wise to study these, and get them working for you.

Token unkown error in stored procedure when updating on external database

create or alter procedure UPDATECAS (
VNEWSTOCK double precision,
as
declare variable LCCOMANDO2 varchar(256);
begin
LCCOMANDO2 = 'update CAS
set STOCK = STOCK-' || :VNEWSTOCK || '';
for execute statement LCCOMANDO2 on external 'C:\DB\DB.GDB' as
user 'SYSDBA' password 'masterkey'
suspend;
end
I am using Firebird and I want to create a stored procedure to do an update in another database and I do not understand what I am missing because when compiling it gives me the following error:
can't format message 13:896 -- message file C:\WINDOWS\firebird.msg not found.
Dynamic SQL Error.
SQL error code = -104.
Token unknown.
suspend
The error code 13:896 is usually shown as error code 336397184, which translates to message "Invalid token". (as an aside: The "can't format message" error is an indication that you're using a fbclient.dll that can't find the firebird.msg file with error messages, or you're using an older version that doesn't contain the specific message)
In this specific case, the problem is that you made a syntax error: your statement is missing the word DO, as shown in FOR EXECUTE STATEMENT in the Firebird 2.5 Language Reference. As a result, the Firebird parser finds a SUSPEND in a position it doesn't expect it (it either expects DO, or another token from the FOR EXECUTE STATEMENT syntax). The - obvious, but incorrect - fix would be:
for execute statement LCCOMANDO2 on external 'C:\DB\DB.GDB' as
user 'SYSDBA' password 'masterkey' do
begin
suspend;
end
Note: enclosing the suspend; in begin ... end is not necessary, but in my opinion it improves readability.
This would solve the immediate problem, but will then result in another error, because the FOR EXECUTE STATEMENT is intended to execute statements that produce a result set, and UPDATE does not produce a result set.
Instead, you need to use EXECUTE STATEMENT without FOR. I would also highly recommend that you appropriately parameterize your update statement, instead of concatenating values into the query string. Given your stored procedure doesn't produce any data (it has no RETURNS clause), use of the SUSPEND clause is also inappropriate.
The final code should be something like:
create or alter procedure UPDATECAS (VNEWSTOCK double precision)
as
begin
execute statement ('update CAS set STOCK = STOCK - :newstock') (newstock = VNEWSTOCK)
on external 'C:\DB\DB.GDB' as user 'SYSDBA' password 'masterkey';
end
Be aware though, that using double precision for something that is stock doesn't seem appropriate. Usually stock is discrete units, so INTEGER or BIGINT would be more appropriate, or if you need decimal values, the exactness of DECIMAL (or NUMERIC) is probably better than the inexactness of DOUBLE PRECISION.

How to create a DB2 stored procedure in SQL with following conditions?

I am new to this. Please do not downvote question.
I have created a table named 'FormData' which contains following fields
Reviewer, AgencyName, Name, Email, Phone and all of type varchar.
I have to retrieve all rows from FORMDATA where Reviewer is equal to the value of Reviewer given by the user.
I have written following code but I am not getting what is the problem in this.
CREATE PROCEDURE GetFormData( INOUT Reviewer varchar,
INOUT AgencyName varchar,
INOUT Name varchar,
INOUT Email varchar,
INOUT Phone varchar)
LANGUAGE SQL
P1:BEGIN
DECLARE v_Reviewer varchar;
SET v_Reviewer=Reviewer;
SELECT * FROM TRAININGDB.FormData
WHERE Reviewer=v_Reviewer;
END P1
The error I received after this is:
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0104N An unexpected token "END-OF-STATEMENT" was found following "Reviewer
varchar"
We are using DB2 in WebSphere server and the remaining details are.
Product Identifier: SQL09075
DB2 v9.7.500.702
JDK 1.6
OS: Windows 7
There are several problems with your code, and also you omit key details from your question ( the tool(s) you are using/versions/operating-system details).
SQL0104N happens because you did not configure the tool you used to submit the statement to specify an alternate statement delimiter. Inside the procedure the intra-statement delimiter is semicolon, but you need an additional delimiter to mark the end of the procedure (and configure the tool that submits the statement to specify that additional delimiter).
As you are learning, the best advice is to study the IBM example SQL PL stored procedures , and make them work on your environment. These are visible both in the online Knowledge Center for your version of DB2 and they are also installed on any DB2 Linux/Windows/Unix server.
Below is an example of your procedure if you submit it from the shell command line on Unix or Windows (db2cmd.exe or the bash shell). Lookup the syntax for all that is different from your versions and adjust it as needed.
--#SET TERMINATOR #
CREATE or replace PROCEDURE GetFormData( IN p_Reviewer varchar(20))
result sets 1
specific GetFormData
LANGUAGE SQL
P1:
BEGIN
declare c1 cursor for SELECT * FROM TRAININGDB.FormData WHERE Reviewer=p_Reviewer;
open c1;
END P1
#

Creating parameterized cursors in DB2

I'm Facing below error:
An unexpected token "(" was found following " CURSOR ". Expected tokens may include: "CURSOR". SQLSTATE=42601
And I'm just trying to create a simple cursor, actually the example one found here in IBM documentation.
Cursor declaration looks something like:
DECLARE
CURSOR c1 (max_wage NUMBER) IS
SELECT * FROM emp WHERE sal < max_wage;
Not sure if this is do to the version of DB2 being used or not. Can anyone suggest maybe an alternative to creating a parameterized cursor?
You are trying to use PL/SQL syntax in DB2. This requires changes to the server environment. If you want to support the Oracle datatypes as well, the database must be created with the right settings, too. See this article for more details. The summary of that article is:
Open a DB2 Command Window (in Administrator mode)
Run db2start
Run db2set DB2_COMPATIBILITY_VECTOR=ORA
Run db2set DB2_DEFERRED_PREPARE_SEMANTICS=YES
Run db2stop
Run db2start
Execute your PL/SQL statements, e.g. in a DB2 CLP (run db2 -tv) command window.
Note that you should run
SET SQLCOMPAT PLSQL; in your DB2 CLP before trying PL/SQL. This enables using a forward slash (/) as a PL/SQL statement terminator. You should then obviously also then actually terminate your command with a forward slash :)
Here's an example taken from your link, modified to work with the default SAMPLE database in DB2:
SET SQLCOMPAT PLSQL;
DECLARE
my_record emp%ROWTYPE;
CURSOR c1 (max_wage integer) IS
SELECT * FROM employee WHERE salary < max_wage;
BEGIN
OPEN c1(40000);
LOOP
FETCH c1 INTO my_record;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Name = ' || my_record.firstnme || ', salary = '
|| my_record.salary);
END LOOP;
CLOSE c1;
END;
/
If you don't want to do all the above, then use the standard DB2 cursor syntax:
DECLARE [cursor name] CURSOR FOR [...]
...but that doesn't support parameterized cursors. To do so, I'd recommend creating a stored procedure taking the parameter. This stored procedure can then create a cursor using that parameter directly in the SQL.

Why doesn't this PL/SQL procedure work?

I have a cursor which returns two values: one which I will use (and therefore will assign to an out variable) and another which I've only had returned to make the ROWNUM thing work.
If I run the cursor as a query, it works as expected. But if I execute the procedure the out variable comes empty. Is my approach somehow not supported? I mean, returning two values but only using one of them?
Here is my procedure code: (Don't delve too much on the query itself. It works, I know it's a bit ugly but it works. It was the only way I found to return the second-last row)
procedure retorna_infos_tabela_164(i_nip in varchar,
o_CODSDPANTERIOR out number) is
cursor c_tabela_164 is
select *
from(
select CODSDP,ROWNUM rn
from
(
select NRONIP,CODTIPOMOV,CODSDP
from TB164_HISTORICOMOVIMENTACOES
where NRONIP = i_nip and
CODTIPOMOV='S1'
order by DTHMOV desc
)
)
where rn=2;
v_temp_nr number;
begin
open c_tabela_164;
fetch c_tabela_164 into o_CODSDPANTERIOR,v_temp_nr;
close c_tabela_164;
end retorna_infos_tabela_164;
EDIT The way I've tried to run this procedure was by dbms_output.put_line(o_CODSDPANTERIOR) which didn't work. Then I googled a little bit and saw I should TO_CHAR() my var first and then have it output. Didn't work either.
There's no problem with passing a number to DBMS_OUTPUT.PUT_LINE. Oracle will silently convert other built-in types to VARCHAR2 using the default format. You only need to use TO_CHAR if you want to control the format used -- which is often a good idea, but not generally necessary.
One possibility, though, is that you are not seeing the output because you have not enabled it. If you are running your test in SQLPlus, make sure you SET SERVEROUTPUT ON before running code that includes DBMS_OUTPUT calls. If you are using some other client, consult its documentation for the proper way to enable DBMS_OUTPUT. (You can of course test if it's enabled by adding another call to output a string literal.)
There's nothing inherently wrong with the technique you're using to populate the out parameter. However, it's not necessary to return two columns from the cursor; your select * could simply be select CODSDP. You seem to be under the misconception that any column referenced in the predicates has to be in the select list, but that's not the case. In your innermost query, the select list does not need to include NRONIP or CODTIPOMOV, because they are not referenced in the outer blocks; the WHERE clause in that query can reference any column in the table, regardless of whether it is in the select list.
So, my first guess is that you simply don't have server output enabled. The only other possibility I can think of right now is that you're running your query and the procedure in two different sessions, and one of them has uncommitted transaction against the table, so they are actually seeing different data.
If those suggestions don't seem to be the problem, I'd suggest you run your tests of the standalone query and the procedure in a single SQLPlus session, then copy and paste the entire session here, so we can see exactly what you're doing.
I'm sorry I've had you guys take the time to answer me when the answer was something to do with the tool I'm using. I hope all you guys have learnt something.
The query does work for me at least, I've not come across any edge cases where it doesn't work, but I haven't tested it exhaustively.
The problem was that TOAD, the tool I'm using to run the procedures, sometimes populates the procedures with the parameters I tell it to but sometimes it doesn't. The issue here was that I was trying to execute the procedure with no parameters, yielding no results...
Lesson Learnt: double check the generated procedure code when you run a Procedure using Right Click > Run Procedure on TOAD version 9.