# OQL

## Features

- Select queries with navigation over arbitrarily many class relationships
- Inheritance and polymorphism always assumed
- Type specialization (downcasting) in navigation
- Ordering and grouping
- Unions of select queries
- Objects, values, or aggregate functions in results
- Windowing of the result set (offset and limit)
- Parameterized queries

## Syntax

This is an informal and not strictly precise definition of the syntax, yet it is practically sufficient as a quick reminder. The syntax is generally very close to that of SQL, and the following description illustrates the supported features.

```
SELECT [DISTINCT] expression [[AS] alias], expression [[AS] alias]...
```

FROM term [[AS] alias], term [[AS] alias]...

[WHERE condition]

[GROUP BY expression [[AS] alias], expression [[AS] alias]...]

[HAVING condition]

[UNION [DISTINCT | ALL] query]

[ORDER BY expression [ASC | DESC], expression [ASC | DESC]...]

[LIMIT size | LIMIT ALL]

[OFFSET offset]

### Navigation terms

- Class name (identifiers may be quoted with "", e.g. "from")
- term.property
- term:DowncastClass.property

### Expressions

- * (in SELECT only)
- term.* (in SELECT only)
- term
- term.property
- constant
- #parameter#
- arithmetic operators: +, -, *, /, MOD
- aggregate functions: MAX, MIN, SUM, AVG, COUNT, COUNT(*), COUNT(DISTINCT)

### Conditions

- equality and inequality: =, ==, !=, <>
- comparison: <, <=, >, >=, BETWEEN ... AND ...
- LIKE 'pattern', LIKE #param#
- IN (constant, constant...)
- IS NULL
- Boolean operators: AND, OR, NOT

### Constants

(type qualifier may be omitted if type can be inferred from the context):

- Text: 'text'
- Boolean: true, false
- Integer:
- decimal: 42
- hexadecimal: 0x2A, x'2A'
- octal: 052
- binary: 0b101010, b'101010'

- Decimal: 42.0, decimal'42.0', currency'42.0'
- Real: 42.0, 6.022E+23, real'42.0'
- Date: date'yyyy-MM-dd'
- Time: time'HH:mm:ss.SSS'
- DateTime: datetime'yyyy-MM-dd HH:mm:ss.SSS', timestamp'yyyy-MM-dd HH:mm:ss.SSS'
- Enumerations: enumClassName'value' (e.g. Status'APPROVED')

## Semantics

This is just a brief description of the semantics of OQL queries, especially of those parts that are specific to OQL or not completely analogue to the counterparts in SQL. These explanations should be sufficient to those already familiar with SQL or HQL, while in-depth and precise explanations of the semantics of OQL queries can be found in the book: Milicev D., Model-Driven Development with Executable UML, Wiley/Wrox, July 2009, ISBN 9780470481639

The basic form of an OQL SELECT query is the same as in SQL:

`SELECT projectionClause FROM navigationClause WHERE selectionClause`

For example:

```
SELECT p, p.name, p.email
```

FROM Course c, c.students p

WHERE c.name = 'Introduction to OQL'

Therefore, an OQL query has three main parts: the navigation clause (

following *navigationClause*`FROM`

), the selection clause (

following *selectionClause*`WHERE`

), and the projection clause (

following *projectionClause*`SELECT`

).

The navigation clause specifies navigation over the object structure. The navigation designates a type of tuples of values, each value representing a placeholder for an instance of a certain type. The navigations over properties also introduce implicit constraints over the returned tuples. The constraints enforce that the objects referred to by the placeholders are linked by links of the corresponding relationships. In the previous example, each tuple designated by the navigation clause has two values named `c`

and `p`

, where `c`

is a placeholder for an object of `Course`

, while `p`

is a placeholder for an object of `Person`

(the type of the navigated property `students`

). The implicit restriction introduced by the navigation clause is that the objects referred to by `p`

and `c`

are linked, so that `p`

is an element of the collection designated by `c.students`

.

In short, the navigation clause defines a collection of tuples of values, one value for each term in the clause (the terms are separated by commas). The value in the tuple is named by the optional alias provided in the term, and can be referred to by that name in the clauses of the same query. Therefore, the navigation clause also introduces the names of the values in the tuple, the scope of the names being the same query.

As it can be concluded, the collection of tuples is obtained by the so-called *inner join*. (All OQL joins are inner joins. We will support outer joins in future versions.) This means that the collection of the tuples designated by the navigation clause consists of a sub-collection of a Cartesian product of all existing instances of the types, such that the values (referring to instances of classifiers) implied by the terms satisfy the following constraint: If a term in the clause specifies navigation over a property, the value implied from it must be an element of the collection designated by the referred property.

For the previous example, the resulting collection of tuples defined by the navigation clause is the collection of tuples `(c, p)`

, where `c`

is an object of `Course`

, while `p`

is an object of `Person`

(the type of the navigated property `students`

), and `p`

is an element of `c.students`

. On the other hand, consider the tuple defined by the following `FROM`

navigation clause, assuming that students of a course are objects of class `Person`

, and the class `Teacher`

is a subclass of the class `Person`

:

`Course c, c.students:Teacher t, c.name n1, t.taughtCourses tc, tc.name n2`

This consists of the named elements as shown in the following table:

Name | Type | Additional Implied Constraint |
---|---|---|

`c` | `Course` | None |

`t` | `Teacher` | `t` is in `c.students` |

`n1` | `String` | `n1` is in `c.name` |

`tc` | `Course` | `tc` is in `t.taughtCourses` |

`n2` | `String` | `n2` is in `tc.name` |

As a result, the navigational clause defines a collection of all tuples retrieved from the object space satisfying the described criteria. In the general case, the collection is a bag, because the collections designated by the navigation terms can be bags, and the navigations can be combined over several properties (for example, `t.taughtCourses.teachers.taughtCourses`

). Each value in the tuple is of the type defined in the term, and is always of cardinality exactly one (that is, it is never a `null`

).

There are two kinds of terms allowed in the navigation clause.

The first kind of term is a simple class reference. The term simply specifies a class and an optional alias. An example is the term `Course c`

. The type of the value designated by such a term is that class.

The second kind is a term that defines navigation over properties of objects. The navigation must start with a name defined by another term before this term. For example, the following terms define navigations:

`c.students:Teacher t, c.name n1, t.taughtCourses tc, tc.name n2`

A term can include a navigation chain over several properties, as shown in the following example:

```
t.taughtCourses.students
```

t.taughtCourses.students.attendedCourses

t.taughtCourses.students.attendedCourses.name

t.taughtCourses.students.attendedCourses.students

t.taughtCourses.students.attendedCourses.students.name

The number of hops over properties in a navigation chain can be arbitrary, but finite.

The type of the term is that of the last property in the navigation chain. Optionally, the type can be specialized to a subtype of the property’s type by the downcasting colon operator:

`t.taughtCourses.students:Teacher`

It specifies that the designated collection is restricted to objects of that subclass only (and all its subclasses; substitution/polymorphism is always assumed). The term above specifies the collection of all students of all courses taught by the given teacher `t`

, but only those students that are also teachers (recall that the class `Teacher`

is derived from the class `Person`

).

The downcasting operator can appear anywhere in the navigation chain. In that case, the further navigation may refer to properties of the specializing type. For example, if `t`

is of type `Teacher`

:

`t.taughtCourses.students:Teacher.taughtCourses.students:Teacher.title`

The collection of values designated by a navigation term is obtained as an inner join of all elements in the chain. For example, the collection designated by this term is obtained by the following set of nested iterations:

`t.taughtCourses.students.attendedCourses`

For each instance `t`

of the type specified by the term that defines `t`

(`Teacher`

in this case) — for each element `e1`

in `t.taughtCourses`

, for each element `e2`

in `e1.students`

, for each element `e3`

in `e2.attendedCourses`

, return `e3`

. It is obvious that if the chain has more than one navigation hop, the resulting collection can be non-unique (that is, a bag) in a general case, since the resulting values can be multiplied.

The selection clause after `WHERE`

constrains further the resulting collection of tuples by specifying an expression. The expression must return a Boolean result. The expression can refer to all the names of the values in the tuple defined by the navigation clause, or to a parameter of the query. Parameters are arbitrary identifiers enclosed in # signs (for example, `#nameParam#`

). Actual values of the parameters will be provided by the invocation of the query through an API call, when the query is executed. The `WHERE`

expression is evaluated for every tuple in the collection designated by the navigation `FROM`

clause. The resulting collection of tuples is reduced by the selection `WHERE`

clause to all these and only these tuples for which the expression evaluates to true.

Finally, the projection clause following `SELECT`

simply projects the resulting tuple to another tuple by keeping some of the values in the tuple and removing the others, or even adding new ones. Think of the collection of the tuples resulting from the rest of the query (the navigation and selection clauses) as a table with columns identifying values and rows representing the selected tuples. Then, the projection clause simply removes some columns, while keeping the others or adding new ones. The values can be the names of the terms from the navigation `FROM`

clause or their properties. All rows are preserved (no duplicates are removed, unless the `DISTINCT`

specifier is used). Optionally, the projection clause renames some columns by providing different names (aliases) for some values in the tuples.

The resulting collection of tuples can be grouped or ordered, as in SQL. The resulting set can be limited to a subcollection (a window) by providing the optional `OFFSET`

(0-based, offset 0 is default) and `LIMIT`

(the size of the window). For example, the following query returns the third group of 10 students (as objects) of the given course, ordered by their names:

```
SELECT p, p.*
```

FROM Course c, c.students p

WHERE c.name = 'Introduction to OQL'

ORDER BY p.name

LIMIT 10 OFFSET 20

A union can be made of queries that have homogeneous result sets. This means that the tuples of the results of the queries in the union must have the same number of columns, and the corresponding columns must be of the same type or of a type with a common supertype; the resulting union will then have that common supertype as each column type. The resulting union is a true set union with distinct values (`DISTINCT`

is default), unless the `ALL`

specifier is used.