Copyright © 2018, 2019 WSO2
Licensed under the Creative Commons Attribution-NoDerivatives 4.0 International license
This document describes features implemented experimentally in Ballerina 1.0.
behavioral-type-descriptor := ... | stream-type-descriptor
A value of type
stream<T> is a distributor for values of type
T: when a value v of type T is put into the stream, a function will
be called for each subscriber to the stream with v as an argument. T must be a
A value belongs to a type
stream (without the type-parameter)
if it has basic type stream.
A new stream can be constructed using a
expression := ... | table-query-expr
fromquery-source [query-join-type query-join-source] [query-select] [query-group-by] [query-order-by] [query-having] [query-limit] query-source := identifier [
asidentifier] [query-where] query-where :=
whereexpression query-join-type := [([
joinquery-join-source := query-source
onexpression query-select :=
*| query-select-list) query-select-list := expression [
asidentifier])* query-group-by :=
,identifier)* query-order-by :=
descending)])* query-having :=
havingexpression query-limit :=
Query expressions bring language integrated SQL-like querying to Ballerina tables.
statement := ... | lock-stmt | forever-stmt | transaction-stmt | transaction-control-stmt
A lock statement is used to execute a series of assignment statements in a serialized manner. For each variable that is used as an L-value within the block statement, this statement attempts to first acquire a lock and the entire statement executes only after acquiring all the locks. If a lock acquisition fails after some have already been acquired then all acquired locks are released and the process starts again.
}streaming-query-pattern := streaming-query-expr
)block-stmt streaming-query-expr :=
from(sq-source [query-join-type sq-join-source]) | sq-pattern [query-select] [query-group-by] [query-order-by] [query-having] [query-limit] [sq-output-rate-limiting] sq-source := identifier [query-where] [sq-window [query-where]] [
asidentifier]* sq-window :=
windowfunction-call-expr sq-join-source := sq-source
onexpression sq-output-rate-limiting := sq-time-or-event-output | sq-snapshot-output sq-time-or-event-output := (
everyint-literal (time-scale |
events) sq-snapshot-output :=
everyint-literal time-scale time-scale :=
yearssq-pattern := [
every] sp-input [sp-within-clause] sp-within-clause :=
withinexpression sp-input := sp-edge-input ((
,) sp-input |
andsp-edge-input) | (
forint-literal time-scale) | [sp-edge-input (
or) ] sp-edge-input |
)sp-edge-input := identifier [query-where] [sp-int-range-expr] [
asidentifier] sp-int-range-expr :=
The forever statement is used to execute a set of streaming queries against some number of streams concurrently and to execute a block of code when a pattern matches. The statement will never complete and therefore the worker containing it will never complete.
transactiontrans-conf? block-stmt trans-retry? transaction-control-stmt := retry-stmt | abort-stmt trans-conf := trans-conf-item (
,trans-conf-item)* trans-conf-item := trans-retries | trans-oncommit | trans-onabort trans-retries :=
=expression trans-oncommit :=
=identifier trans-onabort :=
=identifier trans-retry :=
onretryblock-stmt retry-stmt :=
A transaction statement is used to execute a block of code within a 2PC transaction. A transaction can be established by this statement or it may inherit one from the current worker.
If no transaction context is present in the worker then the transaction statement starts a new transaction (i.e., becomes the initiator) and executes the statements within the transaction statement.
Upon completion of the block the transaction is immediately tried to be committed. If the commit succeeds, then if there's an on-commit handler registered that function gets invoked to signal that the commit succeeded. If the commit fails, and if the transaction has not been retried more times than the value of the retries configuration, then the on-retry block is executed and the transaction block statement will execute again in its entirety. If there are no more retries available then the commit is aborted the on-abort function is called.
The transaction can also be explicitly aborted using an abort statement, which will call the on-abort function and give up the transaction (without retrying).
If a retry statement is executed if the transaction has not been retried more times than the value of the retries configuration, then the on-retry block is executed and the transaction block statement will execute again in its entirety.
If a transaction context is present in the executing worker context, then the transaction statement joins that transaction and becomes a participant of that existing transaction. In this case, retries will not occur as the transaction is under the control of the initiator. Further, if the transaction is locally aborted (by using the abort statement), the transaction gets marked for abort and the participant will fail the transaction when it is asked to prepare for commit by the coordinator of the initiator. When the initiating coordinator decides to abort the transaction it will notify all the participants globally and their on-abort functions will be invoked. If the initiating coordinator decides to retry the transaction then a new transaction is created and the process starts with the entire containing executable entity (i.e. resource or function) being re-invoked with the new transaction context.
When the transaction statement reaches the end of the block the transaction is marked as ready to commit. The actual commit will happen when the coordinator sends a commit message to the participant and after the commit occurs the on-commit function will be invoked. Thus, reaching the end of the transaction statement and going past does not have the semantic of the transaction being committed nor of it being aborted. Thus, if statements that follow the transaction statement they are unaware whether the transaction has committed or aborted.
When in a participating transaction, a retry statement is a no-op.
The transaction context in a worker is always visible to invoked functions. Thus any function invoked within a transaction, which has a transaction statement within it, will behave according to the "participated transactions" semantics above.
The transaction context is also propagated over the network via the Ballerina Microtransaction Protocol [XXX].
The stream basic type has a lang library module