This topic describes the StreamBase expression language and each of the built-in functions that you can use with StreamBase applications. In EventFlow applications, you use StreamBase functions in operators (except Heartbeat, Metronome, Split, and Union, which do not take an expression). You can also use StreamBase expressions in statements in StreamSQL applications, as described in the StreamSQL Guide.
Pointer to StreamBase Functions
For information on the functions provided by StreamBase, start with StreamBase Functions.
Also see the Alphabetical Index of StreamBase Functions.
A useful tool for understanding and testing simple expressions is the sbd --eval command, documented in the sbd help topic. Use sbd --eval to test the results of simple expressions as you read this topic, and before using them in your StreamBase applications. For example:
$ sbd --eval "1e1 * (15 % -4)"
(double) 30.0
sbd --eval does not work with aggregate functions. You must evaluate aggregate functions using other methods, such as running a test application and checking the results.
Expressions use the StreamBase static data types. The currently supported types are:
- blob
-
Represents binary data, such as multimedia objects.
- bool
-
Evaluates to
trueorfalse. - int
-
A 4-byte signed integer in the range
-2147483648to2147483647. - double
-
An 8-byte double-precision numeric value.
- long
-
An 8-byte signed integer in the range
-9,223,372,036,854,775,808 [-263]to+9,223,372,036,854,775,807 [263 -1]. - string
-
A text field whose size (up to 2 gigabytes) must be declared.
- timestamp
-
A date and time representation in the format
YYYY-MM-DD hh:mm:ss[.sss][+TTTT]. The maximum precision is milliseconds. - tuple
-
An ordered collection of fields, each of which has a name and a data type. The fields in the collection must be defined by a schema, and can be of any StreamBase data type, including other tuples. The size of a tuple depends on the aggregate size of its fields.
See StreamBase Data Types for details.
StreamBase identifier naming rules apply to the name you assign to any StreamBase component, including schemas, fields, operators, tables, lock sets, modules, and data source names. The rules are:
-
Use only alphabetic characters, numbers, and underscores.
-
The first character must be alphabetic or an underscore.
-
Do not use hyphens or other special characters.
Note
StreamBase creates internal identifiers that include colons, but you cannot use colons in your identifiers.
When you name fields, do not use the following reserved words:
-
blob
-
bool
-
double
-
else
-
false
-
if
-
int
-
long
-
null
-
string
-
then
-
timestamp
-
then
-
true
-
tuple
In an Input Stream's Properties view, StreamBase Studio does not prevent you from specifying a reserved word for a field name. However, a schema that contains reserved words causes one or more typecheck errors in the connected downstream components. The error message in the Typecheck view identifies the offending field's name. Rename the field in the input stream's Properties view.
If a name conflict occurs in a field name that's used in an expression within an operator instance, you can qualify them to clarify the inbound stream you mean.
For example, in the Properties view for a Gather operator, you can qualify the fields
as input[port-number].field-name.
Example: input1.is_alarm, input2.is_alarm,
input3.is_alarm.
In the Properties view for a Join operator, you can qualify the fields in the two
input streams as input1.field-name and
input2.field-name. The input1.field-name refers to a field in the stream
arriving at the top port (#1). The input2.field-name refers to a field in the stream
arriving at the bottom port (#2).
Examples:
input1.SKU input2.SKU
In the Properties view for a Query operator, you can qualify the fields in the two
input streams as input.field-name and
old.field-name. The input.field-name refers to the current input tuple,
while old.field-name refers to the field's
old (prior) value.
Examples:
Table1_current_Name Nasdaq100Table_old_Symbol
You can use +, –, *, /, and %. The ^ expression is not supported.
For example, in the Compliance sample provided with the StreamBase kit, the is_alarm field is a bool. In one of the Compliance application's Map operators, we use this expression for the is_alarm check on each tuple:
((((sector_in_fund_value_t + (shares_traded * price_at_trade)) * 100) / fund_value_t) > 25)
This expression is designed to execute the 25% sector test, where one sector is not
allowed to be more than 25% of the total fund value. is_alarm is set to true if the test
fails.
The modulus operator (%) finds the remainder of a division operation. Division and
modulus are always related such that a/b*b+(a%b) ==
a, where a/b is an integer
division. For example, 15%4 can be resolved as follows:
as:
15 / 4 * 4 + MOD == 15 3 * 4 + MOD = 15 12 + MOD = 15 MOD = 3
This relationship is preserved with negative divisors. As a result, whenever the quotient is negative, the modulus is negative. For example:
15 % 4 = 3 15 % -4 = 3 -15 % 4 = -3 -15% -4 = -3
Also note that if you divide a smaller number by a larger number, the modulus is always the smaller number. For example:
4 % 15 = 4
This behavior may be different than modulus in some programming languages.
Tip
The easiest way to understand StreamBase modulus operations is to try out different expressions using the sbd --eval command.
Unary operators act on only one operand in an expression. –a is valid for integer, double, and long types. !a is valid for the bool type. +a is
not supported.
You can use the <, <=, = or ==, >, >=, and != relational operators. The relational operator <> is not supported.
You can use && or AND, || or OR, and !.
| Logical Operator | Meaning |
|---|---|
| && or AND | AND |
| || or OR | OR |
| ! | NOT |
Note
The evaluation of expressions using && and || will short-circuit. This means that after StreamBase encounters the first term that evaluates as false, no other terms in a statement using && are evaluated. Similarly, evaluation of a statement using || stops after the first true term.
For related information on Boolean logic and nulls, see Using Nulls.
The precedence order of mathematical operators in expressions, from highest to lowest, is as follows:
-
Unary operators: ! and –
The logical negation operator, !, reverses the meaning of its operand.
The unary negation operator, –, produces the negative of its operand.
-
Multiplicative operators: * and / and %
Multiplication: *
Division: /
Modulus, the remainder from division: %
-
Additive operators: + and –
Addition: +
Subtraction: –
-
Relational operators: < and <= and > and >=
Less than: <
Less than or equal to: <=
Greater than: >
Greater than or equal to: >=
-
Equality operator: == or =
-
Not equal: !=
-
Logical AND: && or AND
-
Logical OR: || or OR
You can use parentheses in expressions to override the default precedence.
To recast data types, use one of the StreamBase type conversion functions. For example, to
cast a value to a double in an expression, use the double() function. To cast a value to a string, use the
string() function, and so on. Casting may not be
necessary if type coercion is supported for the data types. See the next section.
Some StreamBase functions support data type coercion of input arguments
from long to double data types. Type coercion is the
implicit conversion of a value from one data type to another. For example, the
floor function is listed in this reference as taking a
double argument. However, you can enter an integer or long value instead: the
function implicitly converts the value to its double equivalent.
There are only two possible data type coercions:
| Input data type | Converts to |
|---|---|
| int | long |
| long | double |
Observe the following rules for coercion:
-
You can supply an int value for a double argument: the intermediate coercion to long happens implicitly.
-
For long-to-double coercion where the precision of the long cannot be preserved in the double, Java rounding rules apply.
This section describes how to specify literals in expressions, for each data type. (For information about the data types themselves, see StreamBase Data Types).
- blob
-
Use the StreamBase blob() function, which converts a string to a blob.
Example:
blob("abcde")creates a blob containing the bytes representing the string"abcde". - bool
-
Use the literals
trueandfalse. - int
-
Enter a number that is in the range of the int data type.
Examples:
0and31337are both ints - double
-
Enter a number using a decimal point, or using scientific notation.
Examples:
10.0and1e1are both doubles. - long
-
Enter a number that is in the range of the long data type, appending L to the number.
Examples:
100Land3147483650Lare both longs.Note
If the L is omitted, StreamBase interprets your number as an int no matter how large the value is.
- string
-
You can use single quotes (
'string') or double quotes ("string") around strings. Escape characters are supported, as follows:Character Results in \" Double quotation mark \' Single quotation mark \n Newline \t Tab \b Backspace \r Carriage return \\ Backslash Examples:
String Literal Results in "He said, \"Hello.\"" He said, "Hello." 'She said, \'Hello.\'' She said, 'Hello.' "A\tB" A<tab>B "A\nB" A<newline>B "C:\\WINDOWS" C:\WINDOWS - timestamp
-
You cannot enter timestamp literals directly in expressions. Instead, use the StreamBase timestamp() function, which converts a string in the following format to a timestamp:
YYYY-MM-DD hh:mm:ss[.sss][+TTTT]
Also see the format_time(), parse_time() and format() functions. The maximum precision for timestamps is milliseconds.
Examples:
"2005-10-08" Implicit time of "00:00:00", local time zone "2005-10-08 13:17" Implicit seconds of "00", local time zone "2005-10-08 13:17:23" Local time zone "2005-10-08 13:17:23.12355" Fractional seconds "2005-10-08 13:17:23" == "2005-10-08 13:17:23" "2005-10-08 24:00:00" == "2005-10-09 00:00:00" "2005-10-08 13:17:23-0500" Explicit time zone (EST in this case) "2005-10-08 13:17-05:00" Explicit time zone, implicit seconds - tuple
-
Define a tuple using this syntax:
tuple (
field_identifierASalias[,...]) [ASalias]The tuple schema, delimited by parentheses, consists of one or more fields separated by commas. Each field identifier resolves to an instance of a StreamBase data type (including another tuple).
Use the AS method to set an alias in the result; however, it can be omitted in anonymous schemas when the field name can be implied from the expression. Omit the outermost alias in EventFlows, where the field name is specified in the GUI. It is required in StreamSQL.
-
This StreamSQL statement defines an output tuple field (named top) that contains a nested tuple:
SELECT tuple(x AS x, tuple(a AS a, b AS b) AS my_nestedtuple) AS top FROM in INTO out;
To define the same output field in an EventFlow, enter
topas the field name in the Properties view table. Enter the same tuple expression, but omit theAS topclause. -
Named schemas can be referenced as nested tuples. In this example, assume that a schema named point has already been defined in the application:
tuple(x AS x, point AS point) AS pointref
-
Fields from named schemas can be referenced in expressions using a dotted notation, like this:
tuple(point.x + point.y) AS pointsum
-
In tuples with anonymous schemas, you can omit field names for direct selection. For example, these two expressions are equivalent:
tuple(x, point.y) tuple(x AS x, point.y AS y)
-
Tuple fields can be useful for grouping fields from various sources. For example, consider this StreamSQL fragment:
CREATE SCHEMA point(x double, y double); CREATE INPUT STREAM input (tag string(12), point); SELECT tuple(tag, point.x AS p) AS mixed FROM input;
The first two statements define a named schema and an input stream that includes it. The last statement defines a nested tuple that includes the tag field and a single field from the
pointschema. It also renames the x field. The expression is equivalent to this:(tag string(12), p double)
To cast a set of values as a tuple that conforms to an existing, named schema, use the tuple(
e[,...]) function. -
You can use nulls in the StreamBase expression language, one for each data type:
blob(null) bool(null) int(null) double(null) long(null) string(null) timestamp(null)
Each null literal is case sensitive; for example, Int(NULL) is invalid. The data type of each null is never implicit:
you must specify which type of null you are using in the expression.
In general, when you apply any arithmetic operator or function with data-type(null) as one of the arguments, the result
is null. Three exceptions are the isnull() and
notnull() functions, which test whether an expression
evaluates to null, and the coalesce() function, which
selects a non-null value from a list of potentially null arguments.
| Expression Example | Result |
|---|---|
| 3 + int(null) | A null int |
| int(null) + int(null) | A null int |
| int(null) + bool(null) | A typecheck error. You cannot add an int and a bool. |
| if bool(null) then 3 else 4 | A null int |
| int(null) == int(null) | A null bool, because null is not equal to itself |
| int(null) != int(null) | A null bool, because null is not equal to itself |
| isnull(int(null)) | A bool that evaluates to true |
| notnull(int(null)) | A bool that evaluates to false |
For related information, please see Using Nulls.
In an expression such as: if p then e1 else e2,
p must be a valid bool expression, and both e1 and e2 must be expressions that have the
same type. If p is true, then e1 will be evaluated and the result returned. If p is
false, e2 will be evaluated and the result returned. In either case the other
sub-expression is not evaluated.
Note
In the StreamBase expression language, each if clause must have a
pair of explicit then and else
clauses. Should you create compound if clauses, to avoid
ambiguity, remember to specify the then and else clauses for each if clause. For an
example, please see the next section.
You can use combinations of if-then and else-if-then statements to form compound conditional expressions.
For example:
if i==0 then "Buy" else if i==1 then "Sell" else if i==2 then
"Hold" else "None of the above"
Here is a second example (indented for clarity), where we nest an if then else in a then clause:
if p1
then
if p2
then 1
else 2
else
if p2
then 3
else 4
Notice how each if clause contains a then clause and an else clause.
You can enter an expression that performs concatenation. For a string variable, the concatenation expression is
stringvar + x
For example: b + 25. For a numeric variable with a
static string, the concatenation expression is
"staticstring" +numvar
For example: "foo" + a. For two variables, the
concatenation expression is
stringvar+numvar
For example: b+a. Note that when you use an expression
to concatenate a number to a string, the total size becomes the original string size
+ 12.
When used with comparison operators ( == != > < <= >= ) you must compare time interval-to-interval, or timestamp-to-timestamp. You cannot use the comparison operators with interval-to-timestamp.
To express constant intervals, you can use the seconds() and minutes() functions.
For example, if you want to add 60 seconds to a timestamp, you can enter expressions
such as:
t + seconds(60) t + minutes(1)
You can declare operator-parameters in the sbd.sbconf
file, and then use them as parameters within StreamBase expressions.
StreamBase Server Configuration
XML explains how to declare operator-parameters.
To then reference a parameter in an expression, wrap the operator-parameter name in braces and prefix the open brace with a dollar sign. If you are referencing an operator-parameter that is defined as a string, use quotes around the entire reference.
For example, consider an sbd.sbconf file that defines
these two operator-parameters:
<operator-parameters>
<operator-parameter name="MyInt" value="2"/>
<operator-parameter name="MyString" value="somestring"/>
</operator-parameters>
You could reference the first parameter (for example, in an output field) using an
expression like 35* ${myInt}. The
expression would evaluate at run time to 70. This
StreamSQL statement references the second parameter:
SELECT * FROM InputStream1 "${MyString}" AS
source
Notice the quotation marks: they are needed so that the expression is resolved as a string.
Note
Expression parameters are distinct from both module parameters, which are described in Using Module Parameters, and StreamSQL CREATE PARAMETER statements:
-
A module parameter is defined only for a parameterized module (or, in StreamSQL, a Java operator or an embedded Java adapter), not globally in the sbd configuration.
-
If you use an expression parameter and a module parameter with the same name, the module parameter value takes precedence.
-
Expression parameters can only be used within expressions. StreamSQL parameters are more flexible: they can be used to represent expressions as well as other parts of a statement.
Note
Expression parameters can be referenced in both EventFlows and StreamSQL applications. However, if you convert an EventFlow application file to a StreamSQL file, any expression parameters are resolved during the conversion; the parameter itself is not preserved.
This section provides reference information for all the StreamBase functions. You can also get help on functions directly in StreamBase Studio when you edit an expression: In the Properties view, the Functions tab shows the syntax of each function and provides editing shortcuts. See Properties View for details.
StreamBase provides two types of functions:
Simple functions are evaluated over one set of arguments,
and return a single result. The strlen() function is an
example of a simple function. Simple functions can be used in expressions for any
StreamBase operator, except Heartbeat, Metronome, and Union, which do
not use an expression.
Aggregate functions are evaluated over multiple sets of
arguments and return a single result. In StreamBase applications,
aggregate functions are used only in Aggregate operators and in Query operators that
do query read operations. The avg() function, which
calculates an average value for tuples in an Aggregate window, is an example of an
aggregate function.
function_name(arg1,arg2,arg3,...)
StreamBase provides several sample applications that feature custom functions for you to load in StreamBase Studio to see how they are built and configured. The custom sample applications are listed in Extending StreamBase Samples.
In addition to the built-in functions provided with StreamBase, you
can call custom functions that you have created by extending the
StreamBase API for Java, C++, or .NET API. (See Developing Custom Functions to
learn how.) After creating a custom function and configuring it in your project,
you can call it in an expression using the calljava()
or callcpp() functions. For example, the following
expression uses calljava() to call a custom class and
its arguments:
calljava(myCustomFunction, x, y)
You can define aliases for your custom functions using the custom-function element in the StreamBase
Server configuration file. This allows you to reference your custom
functions directly, without using a calljava() or
callcpp() function. For example:
myCustomFunction(x, y)
See custom-functions for instructions on defining aliases for your custom functions.
For your convenience, here is a complete, alphabetized index into the available functions provided by StreamBase, with links to the function descriptions in this section. As described in the preceding section, if you do not find a built-in function that you need here, you can use the StreamBase custom function APIs to implement your own function and configure your application to use it. For details, please see these topics in the API Guide:
