Token unkown error in stored procedure when updating on external database - sql

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.

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.

Problem trying to execute a while loop with insert in db2

I am trying to insert entries into a table:
CREATE TABLE MYTABLE (ID INT);
BEGIN
DECLARE CNT INT DEFAULT 0;
WHILE CNT<100 DO
INSERT INTO MYTABLE(ID) VALUES(CNT);
SET CNT = CNT + 1;
END WHILE;
END
What's wrong with the loop? It won't run. The error it shows is:
Error : an unexpected token "End of starement" was found following "re cnt int default 0". Expected tokens may include "psm_semicolon>" sqlcode=-104 sqlstate=42601, driver=3.67.27
Error occured in:
BEGIN
DECLARE CNT INT DEFAULT 0
This is a frequently asked question, you could have found it with search.
You need to tell whatever tool you use to submit the SQL statement that there is an alternative statement terminator (also known as statement separator), and then use that alternative statement terminator at the end of the SQL block , and any standalone non-compound statements.
Many people use # to indicate the end of the block, different tools often suggest different characters.
For squirrel sql, some versions have a "Statement Separator" property on the SQL tab of 'New Session Properties' which you can set to #, and this is effective the next time you open the session. Your code would then have # at the end of the create table statement, plus # once after the end of the block (in the case that you have two statements, one of which is a compound block). If you have more than two statements each compound-block needs its own # terminator at end of block, and each standalone statement (non compound) needs its own #.
The background is that when you have a compound (multi-statement) SQL block in Db2, the semi-colon is the terminator for statements inside the block, but you need a different terminator to indicate the end of the whole block. Without that terminator, you will get an SQL exception.
Different tools have different ways to specify the alternative statement terminator.
Your question does not mention the tool you use to submit the SQL, or your Db2-server platform, which can be relevant sometimes.
If you submit the SQL using the Db2 command-line-processor (at the shell command line on Windows, Linux/Unix), then you can specify the alternative statement terminator either on the db2 command line ( -td#) , or on the fly inside the file (as long as that file is submitted by the db2 CLP) that contains the SQL statements by having a line that reads --#SET TERMINATOR # . You can use this as often as you like inside a file sent to the CLP, each with a different terminator if necessary and if impacts only the subsequent statements after that line until the next terminator is specified. This method is not usually applicable to java based tools such as squirrel sql, so use the statement separator property for that.

DB2 stored procedure gave syntax errors

I am creating a stored procedure for db2. But it is giving an error saying that
"SQL Error [42601]: An unexpected token "END-OF-STATEMENT" was found
following "SS_TOKEN_BAK". Expected tokens may include: " END IF"..
SQLCODE=-104, SQLSTATE=42601, DRIVER=4.23.42".
Following is my stored procedure.
CREATE OR REPLACE PROCEDURE TOKEN_CLEANUP_SP
BEGIN
DECLARE batchSize INTEGER;
-- ------------------------------------------
-- CONFIGURABLE ATTRIBUTES
-- ------------------------------------------
SET batchSize = 10000; -- SET BATCH SIZE FOR AVOID TABLE LOCKS [DEFAULT : 10000]
-- ------------------------------------------------------
-- BACKUP IDN_OAUTH2_ACCESS_TOKEN TABLE
-- ------------------------------------------------------
IF EXISTS (SELECT TABLE_NAME FROM TABLES WHERE TABLE_NAME = 'IDN_OAUTH2_ACCESS_TOKEN_BAK')
THEN
DROP TABLE IDN_OAUTH2_ACCESS_TOKEN_BAK;
END IF;
END/
Is anyone face this type of issue. Any help on this would be much appreciated.
Verify that you have the end-of-statement delimiter configured correctly for whatever tool submits the 'CREATE OR REPLACE' procedure. Different tools have different ways to configure the block terminator (alternatively known end of statement delimiter). For command line scripts, use --#SET TERMINATOR / at the start of the file, other ways are possible.
Your code sample shows / as the block terminator, so you might want to use that character as the block delimiter. The semi-colon terminates statements inside the block.
Separately you should see that your code won't compile if the specified table does not exist in the implied schema at compilation time, because you are using static SQL. You may want to use dynamic SQL instead for the drop table statement (search for 'EXECUTE IMMEDIATE' examples).

How to "select" inside a stored procedure or a UDF in DB2 LUW?

I believe this question is very trivial. I' unable to select rows inside a stored procedure that I defined, nor inside a UDF. Here is the syntax that I used:
Create Or Replace Procedure GenerateSequence(
In InternalUnitID SmallInt,
In ObjectTypeID SmallInt)
Language SQL
Dynamic Result Sets 1
Not Deterministic
No External Action
Modifies SQL Data
Commit On Return Yes
Begin
Select Number
From Sequence
Where InternalUnit=InternalUnitID
And ObjectType=ObjectTypeID;
End
If I try to create the above procedure (by putting the definition in a SQL file and running it). I get the following error message:
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 "Select Number From Sequence Where Intern" was
found following "n Return Yes Begin ". Expected tokens may include: "".
LINE NUMBER=21. SQLSTATE=42601
Any clue what can be the cause of this problem?
My environment is DB2 10.5 Express on Windows.
My problem was that I needed to use a cursor in order to return the result set to the caller of the stored procedure.
References:
CREATE PROCEDURE (SQL) statement
Compound SQL (compiled) statement

Compound Statement unable to change the delimiter

I am attempting to run a simple compound statement within the Query Editor of DB Solo 4.2.2
It appears I am unable to properly change the end of line delimiter. I am using DB2. Here is a simple example that gives the error:
--#SET TERMINATOR #
BEGIN ATOMIC
DECLARE id INT;
SET id = 10;
END #
--#SET TERMINATOR ;
Error is:
An unexpected token "INT" was found following "N ATOMIC DECLARE id". Expected tokens may include: "END-OF-STATEMENT"
Thanks in advance
DB2 only allows the semicolon to be used as a delimiter in Compound SQL. The syntax you are using appears to only be valid when using the db2batch utility (which comes with DB2 Linux/Unix/Windows).
Here is some relevant information from the Information Center (this is from the z/OS IC):
How to code multiple statements in an SQL procedure
Use a semicolon
character to separate SQL statements within an SQL procedure.
The procedure body has no terminating character. Therefore, if the
procedure contains only one statement, you do not need to put a
semicolon after that statement. If the procedure consists of a set of
nested statements, you do not need to put a semicolon after the
outermost statement.