BEGIN ... END statement
The BEGIN ... END statement gives the statements defined within the BEGIN and END keywords the status of a single statement.
- Be the body of a function or a procedure
- Have their exceptions handled by a handler
- Have their execution discontinued by a LEAVE statement
Syntax
The second Label can be present only if the first Label is present. If both labels are present, they must be identical. Two or more labeled statements at the same level can have the same label, but this partly negates the advantage of the second label. The advantage is that the labels unambiguously and accurately match each END with its BEGIN. However, a labeled statement nested within Statements cannot have the same label, because this makes the behavior of the ITERATE and LEAVE statements ambiguous.
Scope of variables
DECLARE Variable1 CHAR 'Existing variable';
-- A reference to Variable1 here returns 'Existing variable'
BEGIN
-- A reference to Variable1 here returns 'Existing variable'
DECLARE Variable1 CHAR 'Local variable'; -- Perfectly legal even though
the name is the same
-- A reference to Variable1 here returns 'Local variable'
END;
ATOMIC
If ATOMIC is specified, only one instance of a message flow (that is, one thread) is allowed to execute the statements of a specific BEGIN ATOMIC... END statement (identified by its schema and label), at any one time. If no label is present, the behavior is as if a zero length label had been specified.
CREATE PROCEDURE WriteSharedVariable1(IN NewValue CHARACTER)
SharedVariableMutex1 : BEGIN ATOMIC
-- Set new value into shared variable
END;
CREATE FUNCTION ReadSharedVariable1() RETURNS CHARACTER
SharedVariableMutex1 : BEGIN ATOMIC
DECLARE Value CHARACTER;
-- Get value from shared variable
RETURN Value;
END;
WriteSharedVariable1
and
the function ReadSharedVariable1
are in the same
schema and are used by nodes within the same flow. However, it does
not matter whether or not the procedure and function are contained
within modules, or whether they are used within the same or different
nodes. The integration node ensures that, at any particular time,
only one thread is executing any of the statements within the atomic
sections. This ensures that, for example, two simultaneous writes
or a simultaneous read and write are executed serially. Note that: - The serialization is limited to the flow. Two flows which use BEGIN ATOMIC... END statements with the same schema and label can be executed simultaneously. In this respect, multiple instances within a flow and multiple copies of a flow are not equivalent.
- The serialization is limited by the schema and label. Atomic BEGIN ... END statements specified in different schemas or with different labels do not interact with each other.
Do not nest BEGIN ATOMIC...
END statements, either directly or indirectly, because this could
lead to deadly embraces
. For this reason, do not use a PROPAGATE
statement from within an atomic block.
It is not necessary to use the BEGIN ATOMIC construct in flows that will never be deployed with more than one instance (but it might be unwise to leave this to chance). It is also unnecessary to use the BEGIN ATOMIC construct on reads and writes to shared variables. The integration node always safely writes a new value to, and safely reads the latest value from, a shared variable. ATOMIC is only required when the application is sensitive to seeing intermediate results.
DECLARE LastOrderDate SHARED DATE;
...
SET LastOrderDate = CURRENT_DATE;
...
SET OutputRoot.XMLNSC.Data.Orders.Order[1].Date = LastOrderDate;
Here we assume that one thread is periodically updating LastOrderDate
and
another is periodically reading it. There is no need to use ATOMIC,
because the second SET statement always reads a valid value. If the
updating and reading occur very closely in time, whether the old or
new value is read is indeterminate, but it is always one or the other.
The result will never be garbage. DECLARE Count SHARED INT;
...
SET Count = Count + 1;
Here we assume that several threads
are periodically executing the SET statement. In this case you do
need to use ATOMIC, because two threads might read Count
in
almost the same instant, and get the same value. Both threads perform
the addition and both store the same value back. The end result is
thus N+1 and not N+2. The integration node does not automatically
provide higher-level locking than this (for example, locking covering
the whole SET statement), because such locking is liable to cause deadly
embraces
.
Hint
You can consider the BEGIN ... END statement to be a looping construct, which always loops just once. The effect of an ITERATE or LEAVE statement nested within a BEGIN ... END statement is then as you would expect: control is transferred to the statement following the END. Using ITERATE or LEAVE within a BEGIN ... END statement is useful in cases where there is a long series of computations that needs to be abandoned, either because a definite result has been achieved or because an error has occurred.