Skip to content
Advertisement

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:DBDB.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:WINDOWSfirebird.msg not found.
Dynamic SQL Error.
SQL error code = -104.
Token unknown.
suspend

Advertisement

Answer

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:DBDB.GDB' as
  user 'SYSDBA' password 'masterkey' do
begin
  suspend;
end

Note: enclosing the suspend; in beginend 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:DBDB.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.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement