The switch Statement
switch <expansion> {
case <match-1> {
[ statements-1 ]
}
case <match-2> {
[ statements-2 ]
}
default {
[ statements-3 ]
}
}
A switch
statement causes the server to evaluate <expansion>,
which can be an Attribute-Name or a
dynamic expansion.
The <expansion> cannot be static data, such as a fixed string.
The data is taken from the source, and is compared against <match-1>
and <match-2>, etc. in order to find a match. If no match is found,
then the server looks for the default
case
statement.
The case
statements are matches in a type-specific manner, In most
cases, they are matched via an equality comparison. For IP address
types, the match is done on the network which most narrowly matches
the input. See below for more information.
The switch
statement is largely equivalent to the following use of
if statements:
if (<expansion> == <match-1>) {
[ statements-1 ]
}
elsif (<expansion> == <match-2>) {
[ statements-2 ]
}
else {
[ statements-3 ]
}
However, there are some differences from a series of
if statements. For a switch
statement, the
<expansion> is evaluated only once. For the equivalent
if statement, the <expansion> is evaluated
again for every if. The other difference
performance. Multiple if statements are slow,
and are evaluated in turn. In contrast, case
statements are evaluated only once, and are put into an optimized data
structure.
Performance and Data Types
The switch
keyword will automatically choose an efficient
representation for the set of case statements,
depending on the data type of the <expansion>. This data type can
be forced by using a cast operation, e.g.
switch (ipaddr) %sql.query("SELECT ...") {
For string
and octets
data type, the case
statements are place into a
Red-black tree.
Entries are matched exactly.
For IP address data types (ipv4addr
, ipv6addr
, ipv4prefix
, and
ipv6prefix
), the case statements are placed
into a Patricia / Radix
tree. Multiple networks can be given, including nested networks, so
long as there are no duplicates. Entries are matched on the smallest
network which contains the input data.
Data types which are of the various "integer" types, or ethernet
, or
ifid
are put into a hash table. Entries are matched exactly.
Other data types such as vsa
or group
are not permitted in the
<expansion> field of a switch
statement.
These data structures mean that the <match> lookups are generally
O(lg(N))
in the number of entries. In contrast, a if
/ elsif
chain is much slower, because it is linear in the number of entries.
This efficiency means that it’s possible to create a switch
statement which has a thousands to hundreds of thousands of entries,
with minimal performance overhead. The only cost of having 10,000
entries in a switch
statement is that the server will use more
memory.
Limitations
The match text for the case statement must be static data. That is, the "thing to match" cannot be an attribute reference, or a dynamic expansion.
Duplicate case statements are forbidden and will produce an error.
No statement other than case can appear in a
switch
statement, and the case statement
cannot appear outside of a switch
statement.
For compatibility with version 3, and empty case
statement can also
be used instead of default
. This compatibility will be removed in a
future release.
Examples
switch User-Name {
case "bob" {
reject
}
default {
ok
}
}
switch Framed-IP-Address {
case 192.168/16 {
accept
}
case 192.168.2.0/24 {
reject
}
default {
ok
}
}
switch (ipaddr) %sql.query("SELECT ...") {
case 192.168/16 {
accept
}
case 192.168.2.0/24 {
reject
}
default {
ok
}
}