Jump to: navigation, search

Difference between revisions of "EclipseLink/DesignDocs/312146"

(API)
 
(27 intermediate revisions by the same user not shown)
Line 16: Line 16:
 
| James
 
| James
 
| 0.1 Draft
 
| 0.1 Draft
 +
|-
 +
| 2012-02-07
 +
| James
 +
| 0.2 Updated
 +
|-
 +
| 2012-03-01
 +
| James
 +
| 0.3 Updated
 
|-  
 
|-  
 
|}
 
|}
Line 29: Line 37:
  
 
Other JPQL enhancements:
 
Other JPQL enhancements:
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=243698 allow qualified class names in from clause]
+
* BUG#243698 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=243698 allow qualified class names in from clause]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=293775 allow alias on join fetch]
+
* (fixed - Hermes) - BUG#293775 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=293775 allow alias on join fetch]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=315087 support for cast function]
+
* BUG#315087 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=315087 support for cast function]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=333645 group by fails in in]
+
* (fixed - Hermes) - BUG#333645 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=333645 group by fails in in]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=276147 support union and intersect]
+
* BUG#276147 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=276147 support union and intersect]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=305187 support platform independent functions and custom operators]
+
* BUG#305187 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=305187 support platform independent functions and custom operators]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=321722 support nested join fetches]
+
* (fixed - Hermes) - BUG#321722 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=321722 support nested join fetches]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=321724 support connect by]
+
* BUG#321724 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=321724 support connect by]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=321725 support common functions]
+
* BUG#321725 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=321725 support common functions]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=350597 JPA 2.1 sub select in functions, having, select, from]
+
* (select fixed - Hermes) - BUG#350597 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=350597 JPA 2.1 sub select in functions, having, select, from]
 
* support IN with nested arrays
 
* support IN with nested arrays
* support literal key word
+
* support SQL key word
* support table and column references
+
* support PROPERTY key word
* support asOf
+
* support TABLE and COLUMN references
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=246356 support inner joins in from clause]
+
* support ASOF
 +
* support BATCH FETCH in JPQL
 +
* BUG#246356 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=246356 support inner joins in from clause]
 +
* support 'from ...' without SELECT clause.
 +
* Expression support in Criteria API
 +
* support JPQL without select clause "from Employee e"
  
 
Other JPQL bugs:
 
Other JPQL bugs:
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=346729 incorrect SQL for distinct]
+
* (fixed) - BUG#346729 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=346729 incorrect SQL for distinct]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=331124 join to element collection does not work]
+
* (fixed) - BUG#331124 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=331124 join to element collection does not work]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=331969 join ignored]
+
* (fixed) - BUG#331969 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=331969 join ignored]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=347562 group by ignored] [https://bugs.eclipse.org/bugs/show_bug.cgi?id=227347]
+
* (fixed - Hermes) - BUG#347562 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=347562 group by ignored] [https://bugs.eclipse.org/bugs/show_bug.cgi?id=227347]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=300625 duplicate join in sub select]
+
* (fixed) - BUG#300625 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=300625 duplicate join in sub select]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=267767 package with order fails to parse]
+
* (fixed - Hermes) - BUG#267767 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=267767 package with order fails to parse]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=301905 stack overflow parsing query]
+
* (fixed) - BUG#301905 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=301905 stack overflow parsing query]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=320541 join of map fails]
+
* (fixed) - BUG#320541 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=320541 join of map fails]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=326848 plus not aliasable]
+
* (fixed) - BUG#326848 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=326848 plus not aliasable]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=327848 sub-string fails]
+
* (fixed) - BUG#327848 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=327848 sub-string fails]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=328378 element collection fails with in]
+
* (fixed) - BUG#328378 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=328378 element collection fails with in]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=245652 count distinct fails]
+
* (fixed) - BUG#245652 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=245652 count distinct fails]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=259867 bad sql for in] [https://bugs.eclipse.org/bugs/show_bug.cgi?id=243384] [https://bugs.eclipse.org/bugs/show_bug.cgi?id=314025]
+
* (fixed) - BUG#259867, 243384, 314025 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=259867 bad sql for in] [https://bugs.eclipse.org/bugs/show_bug.cgi?id=243384] [https://bugs.eclipse.org/bugs/show_bug.cgi?id=314025]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=301741 jpql sub selects incorrect]
+
* (fixed - Hermes) - BUG#301741 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=301741 jpql sub selects incorrect]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=307412 member of fails]
+
* (fixed - Hermes) - BUG#307412 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=307412 member of fails]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=354344 concat fails in subquery]
+
* (fixed - Hermes) - BUG#354344 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=354344 concat fails in subquery]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=303268 expression order in jpql causes error]
+
* (fixed) - BUG#303268 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=303268 expression order in jpql causes error]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=303767 join fetch ignored]
+
* (fixed - Hermes) - BUG#303767 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=303767 join fetch ignored]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=357843 dot removes outer join]
+
* (invalid) - BUG#357843 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=357843 dot removes outer join]
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=275449 is not null should be used]
+
* (fixed - Hermes) - BUG#275449 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=275449 is not null should be used]
* from clause not used in select or where is omitted
+
* (fixed - Hermes) - from clause alias not used in select clause or where clause is omitted
 
* object parameters on left
 
* object parameters on left
* [https://bugs.eclipse.org/bugs/show_bug.cgi?id=362063 Nested subselects]
+
* (fixed) - BUG#362063 - [https://bugs.eclipse.org/bugs/show_bug.cgi?id=362063 Nested subselects]
 +
 
 +
JPA 2.1 also define several JPQL enhancements:
 +
* ON clause support
 +
* Support for usage of sub-SELECT in arithmetic and other functions, optionally in SELECT and other clauses.
 +
* FUNCTION support for generic database function usage.
 +
* Support TREAT in WHERE clause.
  
 
= Concepts =
 
= Concepts =
Line 84: Line 103:
 
* Support additional ON clause for a relationship join.
 
* Support additional ON clause for a relationship join.
 
* Support an ON clause on the join for two independent objects.
 
* Support an ON clause on the join for two independent objects.
 +
* Support JPA 2.1 ON clause
 +
* Support JPA 2.1 function key word
 +
* Allow sub-selects in the select clause, having clause, and from clause. ("optionalish" in JPA 2.1)
  
 
= Design Constraints =
 
= Design Constraints =
Line 97: Line 119:
 
* Added support to FunctionExpression and RelationExpression to support object comparisons with IN.  For composite ids as parameters arrayed INs are used, this requires database specific support.
 
* Added support to FunctionExpression and RelationExpression to support object comparisons with IN.  For composite ids as parameters arrayed INs are used, this requires database specific support.
 
* Added support for count distinct with composite ids for MySQL and supporting databases.
 
* Added support for count distinct with composite ids for MySQL and supporting databases.
 +
* Support cast() function.
 +
 +
JPQL
 +
* Support ON clause for join and allow joins of non related entities.
 +
* Support sub-selects in the SELECT, HAVING, and FROM clause.
 +
* Support IN with object expressions.
 +
* Support ORDER BY with object expressions.
 +
* Support = with aliases.
 +
* Support alias on JOIN FETCH.
 +
* Support CAST, EXTRACT functions.
 +
* Support STDDEV, VAR functions.
 +
* Support FUNCTION key word.
 +
* Support OPERATOR key word to allow usage of any ExpressionOperator.
 +
* Support SQL key word for SQL literals and custom SQL.
 +
* Support TABLE() in from clause for data level fragments and mixed queries.
 +
* Support COLUMN() key word for data level fragments and mixed queries.
 +
* Support CONNECT BY PRIOR in  FROM clause.
 +
* Support AS OF in FROM clause.
 +
* Support BATCH FETCH in FROM clause.
 +
* Support arrays comparisons with IN.
 +
* Support FROM without SELECT clause
 +
* Support TREAT in WHERE clause
  
 
= Testing =
 
= Testing =
Line 121: Line 165:
 
** Select e from Employee e order by e.address
 
** Select e from Employee e order by e.address
 
** Select e from Employee e order by e.period
 
** Select e from Employee e order by e.period
 +
* JOIN FETCH alias
 +
** Select e from Employee e join fetch e.address a where a.city = :city order by a.street
 +
** Select e from Employee e join fetch e.phones p order by p.areaCode
 +
** Select e from Employee e join fetch e.manager m join fetch m.address
 +
* sub-SELECTs
 +
** Select e.salary, (Select Max(e2.salary from Employee e2 where e2.address.city = e.address.city) from Employee e
 +
** Select e.id, c.city from Employee e, (Select a.city from Address a) c
 +
* =
 +
** Select e from Employee e, Employee e2 where e = e2 and e = e2.manager
 +
* CAST
 +
** Select e from Employee e where CAST(e.number AS NUMBER) > 100
 +
* FUNCTION
 +
** Select e from Employee e where FUNCTION('UPPER', e.lastName) = 'SMITH'
 +
* OPERATOR
 +
** Select e from Employee e where OPERATOR('NextDay', e.hireDate) = CURRENT DATE
 +
* SQL
 +
** Select e from Employee e where SQL('CAST(? AS NUMBER)', e.id) > 100
 +
* TABLE
 +
** Select s.NAME from TABLE('ALL_STATES') s where s.COUNTRY = 'Canada'
 +
** @AdditionalCriteria("this.tenant IN (Select a.TENANT from TABLE('TENANT') a where a.ACTIVE = true)")
 +
** @AdditionalCriteria("TABLE('PHONE').ACTIVE = true")
 +
* COLUMN
 +
** Select COLUMN('ADDRESS_ID', e) from Employee e
 +
** @AdditionalCriteria("COLUMN('IS_DELETED', e) = false")
 +
* arrays with IN
 +
** Select e from Employee e where (e.deptId, e.empId) IN ((1,5), (6, 8), (9, 2))
 +
* AS OF
 +
** Select e from Employee e AS OF :date where e.id = :id
 +
* CONNECT BY
 +
** Select e from Employee e CONNECT BY e.manager START WITH (e.job = 'President')
 +
* TREAT
 +
** Select p from Project p where Type(p) = SmallProject or Treat(p as LargeProject).budget < 1000
 +
* FROM
 +
** FROM Employee e
 +
 +
Criteria
 +
* query.where(cb.fromExpression(cb.toExpression(root).getField('ROWID').equal(rowid))
  
 
= Native API =
 
= Native API =
Line 127: Line 208:
 
** leftJoin(Expression target, Expression onClause)
 
** leftJoin(Expression target, Expression onClause)
 
** getAlias(Expression subSelect)
 
** getAlias(Expression subSelect)
 +
** operator(String name, List arguments)
 +
** sql(String sql, List arguments)
 +
** cast(Expression, String type)
 
* ObjectLevelReadQuery
 
* ObjectLevelReadQuery
 
** addNonFetchJoin(Expression)
 
** addNonFetchJoin(Expression)
Line 201: Line 285:
 
= Future Considerations =
 
= Future Considerations =
 
* Other JPQL enhancements.
 
* Other JPQL enhancements.
 +
** WITH recursive queries
 +
** WINDOW functions
 +
** SIMILAR, REGEX
 +
** intervals
 +
** sampling
 +
** NULLS FIRST/LAST ordering
 +
** UNIQUE/ALL group by
 +
** grouping sets
 +
** MATCH functions
 +
** statistical functions
 +
** join functions (CROSS, UNION, ...)
 
* Criteria support.
 
* Criteria support.

Latest revision as of 16:37, 1 March 2012

Design Specification: Enhanced JPQL

ER 312146

Feedback

Document History

Date Author Version Description & Notes
2011-10-04 James 0.1 Draft
2012-02-07 James 0.2 Updated
2012-03-01 James 0.3 Updated

Project overview

JPQL currently offers a sub-set of SQL functionality. Some queries that are possible using SQL cannot be defined using JPQL.

It is desired to make EclipseLink's JPQL support be more complete of what is possible in SQL.

A key requirement from users (#1 voted enhancement) is to have ON clause support in JPQL.

Other missing features of SQL could also be added to JPQL, such as sub selects in the SELECT from FROM clauses, and enhanced function support.

Other JPQL enhancements:

Other JPQL bugs:

JPA 2.1 also define several JPQL enhancements:

  • ON clause support
  • Support for usage of sub-SELECT in arithmetic and other functions, optionally in SELECT and other clauses.
  • FUNCTION support for generic database function usage.
  • Support TREAT in WHERE clause.

Concepts

ON clause : the SQL clause part of the FROM clause that defines how to tables are joined, this can be used for both joins and outer joins, but is required for outer joins.

outer join : A join where if a row in the source table has no joined rows in the target table it is still included in the join result with a null row for the target table.

ANTRL : Third party library currently used in EclipseLink for parsing JPQL.

SQL : SQL 2003 BNF

Hermes : New JPQL parser developed by Dali project for parsing JPQL at design time. Currently included in EclipseLink SVN, but not currently used.

Requirements

  • Support additional ON clause for a relationship join.
  • Support an ON clause on the join for two independent objects.
  • Support JPA 2.1 ON clause
  • Support JPA 2.1 function key word
  • Allow sub-selects in the select clause, having clause, and from clause. ("optionalish" in JPA 2.1)

Design Constraints

  • Outer join capabilities differ in different databases.
  • SQL capabilities differ in different databases.

Functionality

  • Extend ObjectExpression to support an onClause, must normalize and copy expression accordingly.
  • Allow ExpressionBuilders and other Expressions to be added to nonFetchJoinExpressions in ObjectLevelReadQuery.
  • Add support for having SubSelectExpressions in SQLSelectStatement's fields and print/normalize accordingly.
  • Added new FromSubSelectExpression to allow SubSelectExpressions to be contained an aliased in a SQLSelectStatement's from clause.
  • Added new FromAliasExpression to allow get() to be used from a FromSubSelectExpression and treated as a QueryKeyExpression aliasing one of the items in the sub-select.
  • Added support to FunctionExpression and RelationExpression to support object comparisons with IN. For composite ids as parameters arrayed INs are used, this requires database specific support.
  • Added support for count distinct with composite ids for MySQL and supporting databases.
  • Support cast() function.

JPQL

  • Support ON clause for join and allow joins of non related entities.
  • Support sub-selects in the SELECT, HAVING, and FROM clause.
  • Support IN with object expressions.
  • Support ORDER BY with object expressions.
  • Support = with aliases.
  • Support alias on JOIN FETCH.
  • Support CAST, EXTRACT functions.
  • Support STDDEV, VAR functions.
  • Support FUNCTION key word.
  • Support OPERATOR key word to allow usage of any ExpressionOperator.
  • Support SQL key word for SQL literals and custom SQL.
  • Support TABLE() in from clause for data level fragments and mixed queries.
  • Support COLUMN() key word for data level fragments and mixed queries.
  • Support CONNECT BY PRIOR in FROM clause.
  • Support AS OF in FROM clause.
  • Support BATCH FETCH in FROM clause.
  • Support arrays comparisons with IN.
  • Support FROM without SELECT clause
  • Support TREAT in WHERE clause

Testing

ON clause needs Expression tests in core testing and JPQL tests in JPA testing. Testing both 1-1, 1-m, relationship and parallel.

  • Added ON clause tests to Expression outerJoin core tests (both inner and outer joins tested).
  • Added FROM and SELECT sub-select tests to Expression subSelects core tests.

API

JPQL

  • ON
    • Select e from Employee e left join e.address a on (a.city = 'Ottawa')
    • Select e from Employee e left join Project p on (p.teamLeader = e)
  • Sub-select
    • Select e.id, (Select a.city from Address a where e.address = a) from Employee e
    • Select e.id, a2.city from Employee e, (Select a.city from Address a) a2
  • IN / NOT IN
    • Select e from Employee e where e.address in (Select a from Address a where city = 'Ottawa')
    • Select e from Employee e join e.phones p where p in :phones
    • Select e from Employee e join e.phones p where p in (:phone1, :phone2)
    • Select e from Employee e where e.address = (Select a from Address a where street = '27 Hastings')
  • ORDER BY (order by objects, Id or all fields for embeddables)
    • Select e from Employee e order by e.address
    • Select e from Employee e order by e.period
  • JOIN FETCH alias
    • Select e from Employee e join fetch e.address a where a.city = :city order by a.street
    • Select e from Employee e join fetch e.phones p order by p.areaCode
    • Select e from Employee e join fetch e.manager m join fetch m.address
  • sub-SELECTs
    • Select e.salary, (Select Max(e2.salary from Employee e2 where e2.address.city = e.address.city) from Employee e
    • Select e.id, c.city from Employee e, (Select a.city from Address a) c
  • =
    • Select e from Employee e, Employee e2 where e = e2 and e = e2.manager
  • CAST
    • Select e from Employee e where CAST(e.number AS NUMBER) > 100
  • FUNCTION
    • Select e from Employee e where FUNCTION('UPPER', e.lastName) = 'SMITH'
  • OPERATOR
    • Select e from Employee e where OPERATOR('NextDay', e.hireDate) = CURRENT DATE
  • SQL
    • Select e from Employee e where SQL('CAST(? AS NUMBER)', e.id) > 100
  • TABLE
    • Select s.NAME from TABLE('ALL_STATES') s where s.COUNTRY = 'Canada'
    • @AdditionalCriteria("this.tenant IN (Select a.TENANT from TABLE('TENANT') a where a.ACTIVE = true)")
    • @AdditionalCriteria("TABLE('PHONE').ACTIVE = true")
  • COLUMN
    • Select COLUMN('ADDRESS_ID', e) from Employee e
    • @AdditionalCriteria("COLUMN('IS_DELETED', e) = false")
  • arrays with IN
    • Select e from Employee e where (e.deptId, e.empId) IN ((1,5), (6, 8), (9, 2))
  • AS OF
    • Select e from Employee e AS OF :date where e.id = :id
  • CONNECT BY
    • Select e from Employee e CONNECT BY e.manager START WITH (e.job = 'President')
  • TREAT
    • Select p from Project p where Type(p) = SmallProject or Treat(p as LargeProject).budget < 1000
  • FROM
    • FROM Employee e

Criteria

  • query.where(cb.fromExpression(cb.toExpression(root).getField('ROWID').equal(rowid))

Native API

  • Expression
    • join(Expression target, Expression onClause)
    • leftJoin(Expression target, Expression onClause)
    • getAlias(Expression subSelect)
    • operator(String name, List arguments)
    • sql(String sql, List arguments)
    • cast(Expression, String type)
  • ObjectLevelReadQuery
    • addNonFetchJoin(Expression)

Examples:

// ON
ExpressionBuilder employee = new ExpressionBuilder();
Expression address = employee.getAllowingNull("address");
employee.leftJoin(address, address.get("city").equal("Ottawa"));
ReadAllQuery query = new ReadAllQuery(Employee.class, employee);
query.addNonFetchJoin(address);
 
// ON
ExpressionBuilder employee = new ExpressionBuilder(Employee.class);
ExpressionBuilder project = new ExpressionBuilder(Project.class);
employee.join(project, project.get("teamLeader").equal(employee));
ReadAllQuery query = new ReadAllQuery(Employee.class, employee);
query.addNonFetchJoin(project);
 
// SELECT SUB-SELECT
ExpressionBuilder employee = new ExpressionBuilder(Employee.class);
ExpressionBuilder address = new ExpressionBuilder(Address.class);
ReportQuery subQuery = new ReportQuery(Address.class, address);
subQuery.addAttribute("city");
subQuery.setSelectionCriteria(employee.get("address").equal(a));
ReportQuery query = new ReportQuery(Employee.class, employee);
query.addAttribute("id");
query.addItem("city", employee.subQuery(subQuery));
 
// FROM SUB-SELECT
ExpressionBuilder employee = new ExpressionBuilder(Employee.class);
ExpressionBuilder address = new ExpressionBuilder(Address.class);
ReportQuery subQuery = new ReportQuery(Address.class, address);
subQuery.addAttribute("city");
subQuery.setSelectionCriteria(employee.get("address").equal(a));
Expression a2 = employee.getAlias(employee.subQuery(subQuery));
ReportQuery query = new ReportQuery(Employee.class, employee);
query.addNonFetchJoin(a2);
query.addAttribute("id");
query.addItem("city", a2.get("city"));

Config files

Documentation

Need to document our BNF, example queries and support beyond JPA 2.0/2.1 in query section.

Open Issues

Issue # Owner Description / Notes
1 Which JPQL parser should be used ANTLR or Hermes?

Decisions

Issue Description / Notes Decision

Future Considerations

  • Other JPQL enhancements.
    • WITH recursive queries
    • WINDOW functions
    • SIMILAR, REGEX
    • intervals
    • sampling
    • NULLS FIRST/LAST ordering
    • UNIQUE/ALL group by
    • grouping sets
    • MATCH functions
    • statistical functions
    • join functions (CROSS, UNION, ...)
  • Criteria support.