The SIRA_PRISE command language

The actual commands of the language

In this section, the SIRA_PRISE commands are presented along with a detailed explanation of their operation. Any pertinent remarks regarding some syntactical category of the grammar will also be presented here.

<SiraPriseCommand> := <Add>|<Delete>|<Update>|<Inquire>|<MultipleAssignment>+

When communicating with a SIRA_PRISE server at the lowest possible level (i.e. without using packages such as the provided java client package), then commands must be sent to the server as a text string, formatted according to the rules of the grammar. Any command must be one of the categories mentioned in the formal grammar.  These will be explained in detail in the pertinent sections below.

All applicable constraints (= all database constraints that might possibly get violated as a consequence of carrying out the given command) are checked after all the insert/delete operations have been done. If a constraint violation is detected, the statement is completely undone. No automatic rollback is done for the entire transaction in which the statement was carried out. If (the detection of) a constraint violation must result in a rollback for the entire transaction, then it is up to the user to issue a rollback message to the server.

<Add> := ASSERT|ADD|CREATE <RelvarName>,<RelationalExpression>

<RelvarName> identifies the relvar to which tuples will be added/asserted (see below), <RelationalExpression> defines which tuples will be added/asserted.

ADD will raise an exception if a tuple is added that is already present in the (body of the relation value currently held in the) updated relvar. The counterpart of ADD that does not raise an exception in that circumstance is ASSERT. In all other respects, ASSERT is identical to ADD. CREATE is a purely syntactical alias for ADD.

For relvars with at least one interval-typed attribute, this rule with respect to ADD is to be interpreted for each point of the interval individually. E.g. adding TUPLE(I(BEGIN(2)END(5))) (where attribute I is of type INTINTERVAL) to a relvar R that currently has value RELATION(TUPLE(I(BEGIN(4)END(8)))) is invalid, but "asserting" that same tuple to R is valid.

If a relvar has interval-typed attributes, ADD will attempt to combine multiple tuples into one, whilst maintaining the same "informational value" within the database. In the above example, the result of the assertion would not be a relation of cardinality 2 in R, but instead the singleton TUPLE(I(BEGIN(2)END(8))) .

This rule is applied irrespective of the number of interval-typed attributes in the updated relvar . Note however, that in the case where a relvar has >1 interval-typed attributes, this implies that there is no "single predictable canonical form" that the relvar value will have after the update. The only guarantee is that if the ADD/ASSERT is accepted, then each "asserted interval point" will be present in (some tuple in the body of the relation value of) the updated relvar, and that SIRA_PRISE will have done the best it could to make the updated relation value "as dense as possible".

<Delete> := UNASSERT|DELETE|REMOVE <RelvarName>,<RelationalExpression>

<RelvarName> identifies the relvar from which tuples will be deleted/unasserted (see below), <RelationalExpression> defines which tuples will be deleted/unasserted.

DELETE will raise an exception if an attempt is made to remove a tuple from the (body of the relation value currently held in the) updated relvar, and that tuple is not there. The counterpart of DELETE that does not raise an exception in that situation is UNASSERT. In all other respects, UNASSERT is identical to DELETE. REMOVE is a purely syntactical alias for DELETE.

For relvars with at least one interval-typed attribute, this rule with respect to DELETE is to be interpreted for each point of the interval individually. E.g. deleting TUPLE(I(BEGIN(2)END(5))) (where attribute I is of type INTINTERVAL) from a relvar that currently has value RELATION(TUPLE(I(BEGIN(4)END(8)))) is invalid, but "unasserting" that same tuple from that same relvar is valid.

Like with ADD, DELETE/UNASSERT will do the best it can to make the relation value after the update "as dense as possible". This is relevant in the case where the relvar has >1 interval-typed attribute. Using a somewhat more concise notation for the interval values, consider a relvar R with value TUPLE(X(1-5)Y(1-3))TUPLE(X(1-3)Y(3-8)) . You can visualise this as two rectangles that together form an L-shaped area. Deleting TUPLE(X(3-5)Y(1-3)) reduces this L-shaped area to a single rectangle. SIRA_PRISE will observe this and merge the two tuples left after the delete into the single TUPLE(X(1-3)Y(1-8)) .

<Update> := UPDATE|MODIFY <RelvarName>,<RelationalExpression>,(<UpdateExpression>+)

 <UpdateExpression> := <AttributeName>(<Expression>)

MODIFY is a purely syntactical alias for UPDATE. The meaning of the three components is as follows :

<RelvarName> is the name of the relvar whose tuples will get updated.

<RelationalExpression> denotes the tuples within that relvar that will get updated. Note in particular that this can be just any relational expression, including a relation value selector, or an expression of the relational algebra involving any number of other relvars. <RelationalExpression> in this context is thus definitely not constrained to being a restrict on the relvar being updated. The only requirement is that any tuple present in (the value denoted by) <RelationalExpression>, must also be present in (the current value of the variable whose name is) <RelvarName>. One peculiar benefit that deserves being spelled out explicitly is the possibility of using a relation value selector here in order to obtain the effect of ‘optimistic locking’ :

  1. Read the database, i.e. issue some restrict on R
  2. Display the tuple(s) on the user’s screen and let him do whatever manipulations he sees fit.
  3. After the user has finished editing, issue an update to R specifying the displayed tuple(s) using a relation value selector. If any other user has impacted that(those) tuple(s) meanwhile in any way, the update will fail, and the user issuing the update can be notified.

<UpdateExpression>+ is a list of expressions that define what updates must be performed on the tuples in <RelvarName> that are denoted by <RelationalExpression>. <UpdateExpression>+ thus identifies :

  1. Which attributes of the ‘updated’ tuples will get a new value.
  2. The formula to be applied to compute the new value of this attribute. This must be an expression whose only allowable variables are references to attributes in the same tuple.

There is no "assert/unassert"-style counterpart to UPDATE. This is theoretically possible, given that UPDATE is nothing more than a shorthand for the combination of some DELETE (or UNASSERT) and some ADD (or ASSERT). This would give rise to four distinct types of UPDATE : DELETE/ADD, DELETE/ASSERT, UNASSERT/ADD, UNASSERT/ASSERT. Of these four, UPDATE behaves like a combination of DELETE/ADD, meaning in particular that the "deleted" tuple is required to exist in the database, and that the "new" tuple is required not to exist in the database at the time of the update.

Note that an update will not be attempted if the new tuple turns out to be equal to the existing tuple. The update command essentially proceeds as follows :

  1. Compute the set of tuples affected
  2. For that set of tuples, compute the set of replacing tuples using the update expressions specified
  3. If a replacing tuple is not equal to its corresponding existing tuple, then delete the existing and add the replacing tuple.

<MultipleAssignment> := CMD(<Add>|<Delete>|<Update>)

SIRA_PRISE supports the concept of multiple assignment, as defined in TTM, in full. Previous versions did not fully apply the "assignment compaction rule" specified in TTM's prescription 21b. This obviously caused previous SIRA_PRISE versions to behave differently in comparison to TTM in some of the cases where a variable is assigned to more than once within the same MA. This has now been remedied in version 1.5.

Consider the MA CMD(ADD R1,...)CMD(DELETE R1,R1) . Previously, the tuples added to R1 in the first step of this MA were NOT "seen" by the second step of this MA, and were thus not deleted from R1, leaving R1 with a non-empty value (it would hold all the tuples added in the first step), whereas the TTM specification requires R1 to be left empty after this assignment. As of SIRA_PRISE V1.5, this requirement is met.

It is not allowed to mingle assignments to catalog relvars and assignments to "regular" user relvars within the same MA. This means it is not possible to define a new relvar (which involves adding tuples to some catalog relvar) and assign it a non-empty value (which involves adding tuples to that new user relvar) within one single MA. Note that before being able to have SIRA_PRISE record a value for a relvar, some physical design details too must be provided too for that relvar.

Apart from those differences, SIRA_PRISE's version of multiple assignment conforms to TTM, thus offering the possibility to do all of the following combinations of operations, and have them behave as if they were one single statement (meaning its effects will be undone entirely if the assignment causes a constraint violation) 

  • Add a set of tuples to (the current value of) a relvar
  • Add a (set of) tuple(s) to one relvar, and add another (set of) tuple(s) to another relvar
  • Add a (set of) tuple(s) to one relvar, and delete another (set of) tuple(s) from the same or any other relvar
  • ...

<Inquire> := INQUIRE|SELECT <RelationalExpression>[,(<AttributeName>+,)]

INQUIRE evaluates its relational expression and sends the result back to the client.

The optional AttributeName list of INQUIRE defines the attributes that will determine the order in which the tuples will be presented in the result. If no AttributeName list is specified, then the ordering of the tuples is undetermined. If an AttributeName list is specified, then determining the position in the result of a tuple t1, relative to that of another tuple t2, is done by first comparing the values that appear in those tuples for the first attribute of the list, if those are equal then of the second attribute of the list, etc. etc. The comparison is done using the comparison operator (GT) of the attribute's type. If no such comparison operator exists (the type is unordered), then the comparison is based on the bit pattern of the encoding of the attribute's value. Note that for this reason, relation-valued attributes cannot be specified in the ordering attribute list. They do have a bit pattern for encoding, but this pattern is not canonical with respect to the relation value encoded (therefore the same "ordering" comparison performed multiple times on the same relation values is not guaranteed to always produce the same results). If all compared attribute values yield "equal", then the relative ordering of the tuples is determined by their internal tuple ID. This makes the ordering deterministic in all cases that do not involve any nonscalar ordering attributes (which is needed for quota query processing, quota query processing being a planned future feature).

<Expression> := <WithExpression>|<PlainExpression>

Expressions in general can make use of the "introduced names" feature, in which case they are a "WITH expression", or they can not make use of that feature, in which case they are just a regular "plain expression".

<WithExpression> := WITH(<WithDef>+(<Expression>))

<WithDef> := <IntroducedExpressionName>(<Expression>)

Often in lengthy expressions, we find that certain sub-expressions have to be repeated a number of times. It would come in handy if a syntactic feature were available that allows to avoid that repetition. WITH expressions are that syntactic feature in SIRA_PRISE. WITH expressions consist of two parts : a list of WithDefs, plus the actual expression.

Each WithDef consists of an introduced name for some subexpression, and the subexpression itself. The introduced name has to obey the usual rules for SIRA_PRISE names. The subexpression itself, obviously, has to be a valid SIRA_PRISE expression.

The concluding (<Expression>) part of the WITH expression can then reference these introduced names just like it would reference a virtual relvar (which is essentially also nothing more than an introduced name for some relational expression). In fact, the only differences between a virtual relvar and an introduced name expression are that :

  1. Virtual relvar expressions have to be relational whereas introduced name expressions can be of any type.
  2. The lifetime of a subexpression in a WITH expression is limited to the lifetime of the WITH expression itself, whereas the virtual relvar definition persists in the catalog until it is explicitly deleted.

<PlainExpression> := <RelationalExpression>|<TuplicalExpression>|<ScalarExpression>

Expressions in general fall apart in three categories : relational expressions (i.e. expressions whose value is a relation), tuple-typed expressions (i.e. expressions whose value is a tuple), and scalar expressions (all the others). This distinction doesn't actually bear great importance, except to make the paragraphs commenting on them manageable ...

<TuplicalExpression> := <AttributeName> | <TupleValueSelector>

Tuple-valued expressions can take on the following forms :

  1. A reference to an attribute in a nonscalar value, where that attribute is tuple-typed
  2. A Tuple value selector

<RelationalExpression> := <RelvarName> | <AttributeName> | <NamedRelationValueSelector> | <UnNamedRelationValueSelector | <RelationalOperatorExpression>

Relational expressions can take on five different forms :

  1. References to database relvars
  2. References to relation-typed attributes within visible scope
  3. Relation value selectors
  4. Relation value selectors using a relvar name as a shorthand for specifying the relation type
  5. Invocations of relational operators

<NamedRelationValueSelector> := <RelvarName>(<TupleValueSelector>*)

If the name of a known relvar is used to specify a relation constant, then the specified relation body must match the heading of that known relvar. The relation type of the relation value selector expression is the same as that of the named relvar.

TABLE_DEE() is a valid relation value selector, because TABLE_DEE is a known relvar name. Note however that TABLE_DEE() is not equal to TABLE_DEE, but instead it ís equal to TABLE_DUM ...

<UnNamedRelationValueSelector> := RELATION([HEADING(<HeadingAttribute>*)]BODY(<TupleValueSelector>*))

In order to specify a relation value of just any relation type, the keyword RELATION must be used. The HEADING portion is optional and can be left out, except in the case when the relation value denoted is the empty relation value. If the HEADING clause is omitted, then the heading is derived from the set of <TupleValueSelector>s provided in the body. Obviously, that set of tuples must constitute a valid relation. If the HEADING clause is explicitly specified, then every <TupleValueSelector> used in the BODY() clause must denote a tuple that conforms to the HEADING specified. As an example, here are three relation value selectors that all denote the same relation value (observe that JAVABACKEDTYPE is a catalog relvar with a single attribute TYPENAME of type NAME) :

RELATION(HEADING(TYPENAME(NAME))BODY(TUPLE(TYPENAME(SOMENAME))))
JAVABACKEDTYPE(TUPLE(TYPENAME(SOMENAME)))
RELATION(BODY(TUPLE(TYPENAME(SOMENAME))))

The empty relation value (i.e. the tupleless relation) of any relation type can then be specified as

RELATION(HEADING(...)BODY())

<HeadingAttribute> := <SHeadingAttribute>|<RHeadingAttribute>
<SHeadingAttribute> := <AttributeName>(<TypeName>)
<RHeadingAttribute> := <AttributeName>(RELATION(HEADING(<HeadingAttribute>*)))

When specifying the heading of a relation, that heading can hold scalar attributes as well as relation-typed attributes. For scalar attributes, the attributename and the (scalar) typename must be specified. But if a relation type has a relation-typed attribute, then selecting a relation value of that type using a relation value selector involves selecting relation values for the relation-typed attribute. So it might appear as if a full RELATION(HEADING(...)BODY(...)) is required within each TUPLE(RELATIONTYPEDATTRIBUTE(...)) construct, as in :

RELATION(HEADING(RVA(RELATION(HEADING(ATTR(INT))))) BODY( TUPLE(RVA(RELATION(HEADING(ATTR(INT))BODY(T(ATTR(3)))))) TUPLE(RVA(RELATION(HEADING(ATTR(INT))BODY(T(ATTR(7)))))) ))

It's easy to see why this is both inefficient and undesirable, so SIRA_PRISE therefore proceeds somewhat differently. In such value selectors, the heading of the RVA relation type is always specified inside the HEADING(...) of the containing relation, and never repeated in the tuple value selectors in the BODY(...) part :

RELATION(HEADING(RVA(RELATION(HEADING(ATTR(INT)))))BODY(TUPLE(RVA(BODY(TUPLE(ATTR(3)))))TUPLE(RVA(BODY(TUPLE(ATTR(7)))))))

<TupleValueSelector> := TUPLE(<AttributeValueSelector>*)
<AttributeValueSelector> := <AttributeName>(<Expression>)

Tuple value selectors essentially consist of a series of attribute value selectors, which in turn name the concerned attribute and state the expression that will select the value that will appear for that attribute in the selected tuple value. Note in particular that the <Expression>s selecting the attribute values need not be literals exclusively. Take a close look at the following example and a (possible) value it produces :

RELATION(HEADING(TYPE(RELATION(HEADING(TYPENAME(NAME))))DBMSFILE(RELATION(HEADING(FILENAME(FILENAME)PAGESIZE(INT))))) BODY(TUPLE(DBMSFILE(DBMSFILE)TYPE(TYPE))))

TYPE DBMSFILE
TYPENAME
FLOATINTERVAL
INTINTERVAL
DECIMAL
INT
BOOLEAN
BITS
LONGINTERVAL
STRING
DATEINTERVAL
RELATION
LONG
NAME
FLOAT
AVERAGE
FILENAME
DECIMALINTERVAL
DATE
PAGESIZE FILENAME
8192 VIT1.ERDB
8192 TRCU.ERDB
32768 VIT2SHIX.ERDB
32768 VIT2MHIX.ERDB
8192 PC.ERDB
32768 DATABASECATALOG.ERDB
32768 VIT2TRIX.ERDB

This value selector selects a singleton relation value of degree two, with the two attributes named 'TYPE' and 'DBMSFILE'. Both attributes are relation-typed. The TYPE attribute has relation values of degree 1, with a single attribute named 'TYPENAME', the DBMSFILE attribute has relation values of degree two, with attributes 'FILENAME' and 'PAGESIZE'. The two attribute values in the singleton relation (the overall expression) are equal to the current value of the TYPE and DBMSFILE relvars of the database, this being achieved with relvar references as the expressions inside the tuple/attribute value selectors.

BTW : this example illustrates how a database can theoretically be seen, in its entirety, as a single tuple with as many relation-typed attributes as there are relvars in the database.

<RelationalOperatorExpression> := <ROjoin> | <ROunion> | <ROintersect> | <ROminus> | <ROxminus> | <ROsemijoin> | <ROsemiminus> | <ROleftjoin> | <ROrename> | <ROproject> | <ROextend> | <ROTransform> | <ROrestrict> | <ROtclose> | <ROgtclose> | <ROdivideby> | <ROgroup> | <ROungroup> | <ROaggregate> | <ROSummarizeBy> | <ROpack> | <ROunpack>

Relational operator invocations are invocations of one of the 19 operators supported by SIRA_PRISE.

<ROjoin> := JOIN(<RelationalExpression>,<RelationalExpression>+,)

JOIN is the 'natural join' operator on relations. The operator is associative, meaning that it is possible to give more than two relations as an argument. Theoretically, the syntax could also provide for monadic and niladic invocations of JOIN (i.e. joins on only one relation and joins on no relation at all), but SIRA_PRISE doesn't support that. The observation that for all R, JOIN(R) = R, and that JOIN() = TABLE_DEE should suffice as an explanation why. We prefer to spend our time trying to solve problems that are a bit more 'real', such as the following :

Allthough SIRA_PRISE is able to find the best evaluation strategy for joins between two arguments, it is not able to do so for joins that have >2 arguments. So the order in which the arguments are listed in an associative join invocation, can significantly impact performance. For good performance, the user is required to write the arguments that "join well" close to one another, and this, perhaps counterintuitively, AT THE END of the list of join arguments. Fortunately, this is about the only bad news there is to mention about (SIRA_PRISE's implementation of) JOIN.

For the formal details of the JOIN operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROunion> := UNION(<RelationalExpression>,<RelationalExpression>+,)

Like JOIN, UNION too is an associative operator. Once again, allthough it would be theoretically possible to support monadic and niladic invocations of this operator, SIRA_PRISE doesn't do that. For all R, UNION(R) = R and UNION() = RELATION(HEADING(...)BODY()) (i.e. the empty relation of the appropriate type).

For the formal details of the UNION operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROintersect> := INTERSECT(<RelationalExpression>,<RelationalExpression>+,)

For this associative operator, the same remark applies as for JOIN and UNION : monadic and niladic invocations of the operator are not supported. INTERSECT(R) = R for all R, and INTERSECT() = RELATION(HEADING(...)BODY(TUPLE(...)...)) , with the relation body growing beyond any computer's memory capacity for all but the simplest relation types.

For the formal details of the INTERSECT operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROminus> := MINUS(<RelationalExpression>,<RelationalExpression>)

For the formal details of the MINUS operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROxminus> := XMINUS(<RelationalExpression>,<RelationalExpression>+,)

XMINUS is the operator that implements the operation known as 'symmetrical difference'. For the formal details of the XMINUS operator, please refer to The operator's javadoc.

It also happens to be the case that this operator is associative. Hence the same remark applies as for JOIN ,UNION and INTERSECT : monadic and niladic invocations of the operator are not supported. XMINUS(R) = R for all R, and XMINUS() = RELATION(HEADING(...)BODY()) .  However, unlike the other associative relational operators, it is also currently not possible to use XMINUS as the aggregation operator in an AGGREGATE invocation that aggregates over relation-valued attributes.  This may be fixed in a future release, but we don't regard this issue as very pressing. (Consider the "meaning" of some tuple appearing in the result of such an "associative" (i.e. >2 arguments) XMINUS invocation : it means that the tuple appeared in any odd number of the XMINUS arguments, but you don't know whether it appeared in 1 or 3 or ... of the arguments, and of course you don't know in which of them.  It doesn't seem like a very useful thing with a compelling need to support it.)

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROsemijoin> := SEMIJOIN(<RelationalExpression>,<RelationalExpression>)

In TTM, the name for the SEMIJOIN operator has recently changed to MATCHING. We prefer to stick with the old names, primarily because the new name for SEMIJOIN's counterpart, SEMIMINUS, includes the word 'NOT' in its new name, which we feel is a word that doesn't belong in names. No piece of furniture is called 'NOT TABLE', no photographer's monopod is called 'NOT TRIPOD', no president of the US is called 'NOT BUSH', no birdwatcher's telescope is called 'NOT BINOCULARS', the boolean value that means "not true" is not called 'NOT TRUE', etc. etc. Other than this psychological naming issue, there is no difference between SIRA_PRISE's SEMIJOIN and TTM's MATCHING.

For the formal details of the SEMIJOIN operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROsemiminus> := SEMIMINUS(<RelationalExpression>,<RelationalExpression>)

SEMIMINUS corresponds to TTM's NOT MATCHING operator. As already indicated, the word 'NOT' in that name is the reason why SIRA_PRISE doesn't follow TTM's recent rename of these operators.

For the formal details of the SEMIMINUS operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROleftjoin> := LEFTJOIN(<RelationalExpression>,<RelationalExpression>,(<AttributeValueSelector>*))

SIRA_PRISE also supports a LEFTJOIN operator. For the formal details of this LEFTJOIN operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROrename> := RENAME(<RelationalExpression>,(<AttributeNamePair>*,))
<AttributeNamePair> := <AttributeName>,<AttributeName>

SIRA_PRISE also supports TTM's RENAME operator. For the formal details of this RENAME operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROproject> := PROJECT(<RelationalExpression>,(<AttributeName>*))

SIRA_PRISE also supports the projection operator of the relational algebra. For the formal details of this PROJECT operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROextend> := EXTEND(<RelationalExpression>,(<ExtendDef>+))
<ExtendDef> := <AttributeName>(<Expression>)

SIRA_PRISE also supports the EXTEND operator of the relational algebra defined in TTM. For the formal details of this EXTEND operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

EXTEND(RESTRICT(TYPEPROPERTIES,ISSCALAR),(SIZERANGE(INTINTERVAL(BEGIN(MINIMUMSIZE)END(PLUS(MAXIMUMSIZE,INT(1)))))))

<ROTransform> := TRANSFORM(<RelationalExpression>,(<TransformDef>*,))
<TransformDef> := <AttributeName>[(<Expression>)]

SIRA_PRISE supports an operator that combines the functionality of EXTEND, PROJECT and RENAME, called TRANSFORM. For the formal details of this operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROrestrict> := RESTRICT(<RelationalExpression>,<ScalarExpression>)

SIRA_PRISE also supports the restriction operator of the relational algebra (in fact a slightly extended version of it). For the formal details of this RESTRICT operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROtclose> := TCLOSE(<RelationalExpression>,(<AttributeNamePair>+,))

SIRA_PRISE supports an operator that performs basic transitive closure. For the formal details of this TCLOSE operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

From the syntax, observe in particular that the degenerate case of an "empty attribute matching list" is not supported.

<ROgtclose> := GTCLOSE(<RelationalExpression>,(<AttributeNamePair>+,),(<GTCloseDef>*))
<GTCloseDef> := <AttributeName>(<Expression>)

SIRA_PRISE supports an operator that performs generalized transitive closure. For the formal details of this GTCLOSE operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

As with "simple" TCLOSE, observe in particular that the degenerate case of an "empty attribute matching list" is not supported.

The process of generalized transitive closure involves matching two distinct tuples from a relation with each other, and when two tuples are matched, constructing a third tuple for inclusion in the result. This will involve evaluating the given expressions in the <GTcloseDef>. In many cases, the expressions will need to reference the attribute values of both of the tuples that were matched. Using simply an attribute name isn't sufficient to make that distinction, since both tuples come from the same relation, thus they both have the same heading, thus they both have the same attributes, thus a simple attribute name reference is ambiguous. A "special" syntactic device is used to make the needed distinction inside expressions that make up a <GTcloseDef> : when referencing the tuple whose "child" attributes matched (this is the tuple that has the "grandparent" for parent), prefix its attribute names with __L__ , when referencing the tuple whose "parent" attributes matched (this is the tuple that has the "grandchild" for child), prefix its attribute names with __R__ .

Example : GTCLOSE(EXTEND(VIRTUALRELVARREFERENCES,EDGECNT(INT(1))),(RELVARNAME,REFERENCEDRELVARNAME),(EDGECNT(PLUS(__L__EDGECNT,__R__EDGECNT))))

<ROdivideby> := DIVIDEBYPER(<RelationalExpression>,<RelationalExpression>,<RelationalExpression>)

For an explanation and examples of this operator, we refer to TTM.

<ROgroup> := GROUP(<RelationalExpression>,(<GroupDef>+))
<GroupDef> := <AttributeName>(<AttributeName>+,)

SIRA_PRISE supports an operator that performs TTM's GROUPing operation. For the formal details of this GROUP operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROungroup> := UNGROUP(<RelationalExpression>,(<AttributeName>))

SIRA_PRISE supports an operator that performs TTM's UNGROUPing operation. For the formal details of this UNGROUP operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

The ungroup operator is, at present, restricted to the ungrouping of at most one relation-typed attribute. TTM is not entirely clear as to how ungroup should proceed in the event of multiple ungroup attributes under certain peculiar conditions (particularly in the event of name-clashes between the attributes of the relation-typed attributes to be ungrouped).

<ROaggregate> := AGGREGATE(<RelationalExpression>,(<AggregationDef>+))
<AggregationDef> := <AttributeName>(<OperatorName>(<Expression>))

SIRA_PRISE supports a form of generic aggregations that are cast in a relational jacket, in the form of its AGGREGATE operator. For the formal details of this AGGREGATE operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROSummarizeBy> := SUMMARIZEBY(<RelationalExpression>,(<AttributeName>*,),(<AggregationDef>+))

SIRA_PRISE also supports a "more complicated" form of generic aggregations in the form of its SUMMARIZEBY operator. This SUMMARIZEBY operator is in fact identical to TTM's, but it may be a bit hard to see because of the great syntactic differences between SIRA_PRISE's expression language and TTM's (Tutorial D). Note that currently, there is no equivalent in SIRA_PRISE for TTM's SUMMARIZE operator (which has the additional PER construct). <RelationalExpression> is the relational expression to be summarized, the <AttributeName>s constitute the "grouping key" in the summary, and the <AggregationDef>s define which summaries are requested. For the formal details of this SUMMARIZEBY operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROpack> := PACK(<RelationalExpression>,(<AttributeName>+,))

If relations involved interval-typed attributes, then previous SIRA_PRISE versions guaranteed that relations produced by relation value selectors, relational operator invocations, ... were always in some packed form. However, if >1 interval-typed attributes were involved, then there was no way to control which particular packed form was chosen. And because the result from PACKing first on X, then on Y will typically not be exactly the same relation as that produced by PACKing first on Y then X (refer to TDATRM/TaRT for further detail and examples), it meant certain relational operator invocations were arguably not fully 100% deterministic.

The now explicitly exposed PACK operator remedies this, by letting the user specify the exact ordering of the PACK attributes in the AttributeName List. All attributes named in the second argument must obviously be interval-typed.

Note that SIRA_PRISE does continue to always (with one exception, see next section) produce relation results that are in packed form. Moreover, the results produced in these cases has also been made deterministic by always taking lexicographical ordering for the PACK attributes.

For the formal details of this PACK operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ROunpack> := UNPACK(<RelationalExpression>,(<AttributeName>+,))

For the formal details of the UNPACK operator, please refer to The operator's javadoc.

For an introductory explanation and examples, please refer to the relevant section in the introduction to the relational algebra.

<ScalarExpression> := <ScalarValueSelector>|<AttributeName>|<ScalarOperatorExpression>

Scalar expressions fall apart in the three categories indicated : scalar value selectors, invocations of scalar operators, and references to attribute names.

References to attribute names are obviously only valid if there is a scope in which those references can be resolved. Such scope is created by invocations of the relational operators RESTRICT, EXTEND, and AGGREGATE (which in turn implies that SUMMARIZEBY also creates scope, as SUMMARIZEBY builds on AGGREGATE).

<ScalarValueSelector> := <TypeName>(<LiteralValue>|<PossRepComponent>+)
<PossRepComponent> := <PossRepComponentName>(<LiteralValue>|<ScalarExpression>)

Scalar value selectors are always introduced by the type name. The specification of the value is either as a literal (e.g. INT(1) ), or else as a list of possrep component value specifications (e.g. DATE(D(...)M(...)Y(...)) ). A Possrep component value specification is always introduced by the possrep component name, followed by either a literal value (e.g. D(1) ) or else any scalar expression that evaluates to a value of the type of the named possrep component (e.g. D(INT(1)) or D(MAX(INT(1),SUB(X,5))) ).

 <ScalarOperatorExpression> := <OperatorName>(<Expression>*,)

Scalar operator expressions are introduced by the operator name, followed by the expressions denoting the operator invocation arguments.

Constructs not explicitly defined in this grammar

<RelvarName>
<AttributeName>
<TypeName>
<PossRepComponentName>
<IntroducedExpressionName>
<OperatorName>
<LiteralValue>

The first six of these are names, and should obey the rules for valid SIRA_PRISE names :

  • The only valid tokens are the alphabetic characters a-z, the digits 0-9, the special characters @ (at sign or amphora), _ (underscore), . (decimal sign or full stop punctuation), and the space character. As for the alphabetic characters, case is irrelevant. SIRA_PRISE treats all names as case-insensitive.
  • They may not exceed the maximum length imposed by SIRA_PRISE on that particular type of name (which is 28 in all of the cases mentioned here).

The <LiteralValue> element is, obviously, subjected only to the rule that it must represent a valid value of the type of the value selector that it appears in.