JBoss.orgCommunity Documentation
Teiid sends commands to your connector in object form. The interfaces for these objects are all defined in the org.teiid.connector.language package. These interfaces can be combined to represent any possible command that Teiid may send to the connector. However, it is possible to notify Teiid that your connector can only accept certain kinds of commands via the ConnectorCapabilities class. See the section on using Connector Capabilities for more information.
The language interfaces all extend from the ILanguageObject interface. Language objects should be thought of as a tree where each node is a language object that has zero or more child language objects of types that are dependent on the current node.
All commands sent to your connector are in the form of these language trees, where the root of the tree is a subclass of ICommand. ICommand has several sub-interfaces, namely: IQueryCommand, IInsert, IUpdate, IDelete, IBatchedUpdate, and IProcedure. Important components of these commands are expressions, criteria, and joins, which are examined in closer detail below. Also see the Teiid JavaDocs for more on the classes and interfaces described here.
An expression represents a single value in context, although in some cases that value may change as the query is evaluated. For example, a literal value, such as 5 represents an integer value. An element reference such as "table.EmployeeName" represents a column in a data source and may logically take on many values while the command is being evaluated.
IExpression
– base expression interface
IElement
– represents an element in the data source
ILiteral
– represents a literal scalar value, but may also be multi-valued in
the case of bulk updates.
IFunction
– represents a scalar function with parameters that are also
IExpressions
IAggregate
– represents an aggregate function which holds a single expression
IScalarSubquery
– represents a subquery that returns a single value
ISearchedCaseExpression
– represents a searched CASE expression. The searched CASE
expression evaluates the criteria in WHEN clauses till one evaluates
to TRUE, then evaluates the associated THEN clause.
A criteria is a combination of expressions and operators that evaluates to true, false, or unknown. Criteria are most commonly used in the WHERE or HAVING clauses.
ICriteria
– the base criteria interface
ILogicalCriteria
– used to logically combine other criteria
INotCriteria
– used to NOT another criteria
ICompoundCriteria
– used to combine other criteria via AND or OR
IPredicateCriteria
– a predicate that evaluates to true, false, or unknown
ISubuqeryCompareCriteria
– represents a comparison criteria with a subquery including a quantifier such as SOME or ALL
ICompareCriteria
– represents a comparison criteria with =, >, <, etc.
IBaseInCriteria
– base class for an IN criteria
IInCriteria
– represents an IN criteria that has a set of expressions for values
ISubqueryInCriteria
– represents an IN criteria that uses a subquery to produce the value set
IIsNullCriteria
– represents an IS NULL criteria
IExistsCriteria
– represents an EXISTS criteria that determines whether a subquery will return any values
ILikeCriteria
– represents a LIKE criteria that compares string values
The FROM clause contains a list of IFromItems. Each IFomItem can either represent a group or a join between two other IFromItems. This allows joins to be composed into a join tree.
IGroup
– represents a single group
IJoin
– has a left and right IFromItem
and information on the join between the items
IInlineView
– represents a group defined by an inline IQueryCommand
A list of IFromItems is used by default in the pushdown query when no outer joins are used. If an outer join is used anywhere in the join tree, there will be a tree of IJoins with a single root. This latter form is the ANSI perfered style. If you wish all pushdown queries containing joins to be in ANSI style have the ConnectorCapability.useAnsiJoin return true. See Command Form Capabilities for more.
IQueryCommand (refered to in SQL as a Query Expression) is the base for both queries and set queries. It may optionally take an IOrderBy (representing a SQL ORDER BY clause) and a ILimit (represent a SQL LIMIT clause)
Each IQuery will have an ISelect describing the expressions (typically elements) being selected and an IFrom specifying the group or groups being selected from, along with any join information. The IQuery may optionally also supply an ICriteria (representing a SQL WHERE clause), an IGroupBy (representing a SQL GROUP BY clause), an an ICriteria (representing a SQL HAVING clause).
An ISetQuery represents on of the SQL set operations (UNION, INTERSECT, EXCEPT) on two IQueryCommands. The all flag may be set to indicate UNION ALL (currently INTERSECT and EXCEPT ALL are not allowed in Teiid)
Each IInsert will have a single IGroup specifying the group being inserted into. It will also a list of IElements specifying the columns of the IGroup that are being inserted into and an IInsertValueSource, which will either be a list of IExpression (IInsertExpressionValueSource) or an IQueryCommand.
Each IUpdate will have a single IGroup specifying the group being updated. The ISetClauseList contains ISetClause entries that specify IElement and IExpression pairs for the update. The IUpdate may optionally provide a criteria specifying which rows should be updated.
Each IDelete will have a single IGroup specifying the group being deleted from. It may also optionally have a criteria specifying which rows should be deleted.
Each IProcedure has zero or more IParameter objects. The IParameter objects describe the input parameters, the output result set, and the output parameters.
This section covers utilities available when using, creating, and manipulating the language interfaces.
The Connector API contains an interface TypeFacility that defines data types and provides value translation facilities.
This ConnectorEnvironment (provided by Teiid on connector start) is a factory to obtain a TypeFacility instance for the connector using the getTypeFacility() method. The TypeFacitlity interface has methods that support data type transformation and detection of appropriate runtime or JDBC types. The TypeFacility.RUNTIME_TYPES and TypeFacility.RUNTIME_NAMES interfaces defines constants for all Teiid runtime data types. All IExpression instances define a data type based on this set of types. These constants are often needed in understanding or creating language interfaces.
In connectors that support a fuller set of capabilities (those that generally are translating to a language of comparable to SQL), there is often a need to manipulate or create language interfaces to move closer to the syntax of choice. Some utilities are provided for this purpose:
Similar to the TypeFacility, you can use the ConnectorEnvironment to get a reference to the ILanguageFactory instance for your connector. This interface is a factory that can be used to create new instances of all the concrete language interface objects.
Some helpful utilities for working with ICriteria objects are provided in the LanguageUtil class. This class has methods to combine ICriteria with AND or to break an ICriteria apart based on AND operators. These utilities are helpful for breaking apart a criteria into individual filters that your connector can implement.
Teiid uses a library of metadata, known as "runtime metadata” for each virtual database that is deployed in Teiid. The runtime metadata is a subset of metadata as defined by models in the Teiid models that compose the virtual database.
Connectors can access runtime metadata by using the interfaces defined in org.teiid.connector.metadata.runtime. This package defines interfaces representing a MetadataID, a MetadataObject, and ways to navigate those IDs and objects.
One language interface, IMetadataReference describes whether a language object has a reference to a MetadataObject. The following interfaces extend IMetadataReference:
IElement
- returns an Element MetadataObjectIGroup
- returns a Group MetadataObjectIProcedure
- returns a Procedure MetadataObjectIParameter
- returns a Parameter MetadataObjectOnce a MetadataObject has been obtained, it is possible to use it metadata about that object or to find other related or objects.
As mentioned in the previous section, a MetadataID is obtained from one of the language objects. That MetadataID can then be used directly to obtain information about the ID, such as the full name or short name.
The RuntimeMetadata interface is passed in for the creation of an Execution. It provides the ability to look up MetadataObjects based on their fully qualified names in the VDB. There are several kinds of MetadataObjects and they can be used to find more information about the object in runtime metadata.
Currently, only a subset of the most commonly used runtime metadata is available through these interfaces. In the future, more complete information will be available.
Obtaining MetadataObject Properties Example
The process of getting an element's properties is sometimes needed for connector development. For example to get the NameInSource property or all extension properties:
//getting the Group metadata from an IGroup is straight-forward IGroup igroup = ... //some group on a command Group group = igroup.getMetadataObject(); //we could also use the runtime metadata RuntimeMetadata rm = ... //Obtained from the creation of the Execution group = rm.getGroup("fully.qualified.name"); String contextName = group.getNameInSource(); //The props will contain extension properties Properties props = group.getProperties();
The Connector API provides a language visitor framework in the org.teiid.connector.visitor.framework package. The framework provides utilities useful in navigating and extracting information from trees of language objects.
The visitor framework is a variant of the Visitor design pattern, which is documented in several popular design pattern references. The visitor pattern encompasses two primary operations: traversing the nodes of a graph (also known as iteration) and performing some action at each node of the graph. In this case, the nodes are language interface objects and the graph is really a tree rooted at some node. The provided framework allows for customization of both aspects of visiting.
The base LanguageObjectVisitor class defines the visit methods for all leaf language interfaces that can exist in the tree. The LanguageObject interface defines an acceptVisitor() method – this method will call back on the visit method of the visitor to complete the contract. A base class with empty visit methods is provided as AbstractLanguageVisitor. The AbstractLanguageVisitor is just a visitor shell – it performs no actions when visiting nodes and does not provide any iteration.
The HierarchyVisitor provides the basic code for walking a language object tree. The HierarchyVisitor performs no action as it walks the tree – it just encapsulates the knowledge of how to walk it. If your connector wants to provide a custom iteration that walks the objects in a special order (to exclude nodes, include nodes multiple times, conditionally include nodes, etc) then you must either extend HierarchyVisitor or build your own iteration visitor. In general, that is not necessary.
The DelegatingHierarchyVisitor is a special subclass of the HierarchyVisitor that provides the ability to perform a different visitor’s processing before and after iteration. This allows users of this class to implement either pre- or post-order processing based on the HierarchyVisitor. Two helper methods are provided on DelegatingHierarchyVisitor to aid in executing pre- and post-order visitors.
The SQLStringVisitor is a special visitor that can traverse a tree of language interfaces and output the equivalent Teiid SQL. This visitor can be used to print language objects for debugging and logging. The SQLStringVisitor does not use the HierarchyVisitor described in the last section; it provides both iteration and processing type functionality in a single custom visitor.
The CollectorVisitor is a handy utility to collect all language objects of a certain type in a tree. Some additional helper methods exist to do common tasks such as retrieving all elements in a tree, retrieving all groups in a tree, and so on.
Writing your own visitor can be quite easy if you use the provided facilities. If the normal method of iterating the language tree is sufficient, then just follow these steps:
Create a subclass of AbstractLanguageVisitor. Override any visit methods needed for your processing. For instance, if you wanted to count the number of elements in the tree, you need only override the visit(IElement) method. Collect any state in local variables and provide accessor methods for that state.
Decide whether to use pre-order or post-order iteration. Note that visitation order is based upon syntax ordering of SQL clauses - not processing order.
Write code to execute your visitor using the utility methods on DelegatingHierarchyVisitor:
// Get object tree ILanguageObject objectTree = … // Create your visitor initialize as necessary MyVisitor visitor = new MyVisitor(); // Call the visitor using pre-order visitation DelegatingHierarchyVisitor.preOrderVisit(visitor, objectTree); // Retrieve state collected while visiting int count = visitor.getCount();
All connectors must return a ConnectorCapabilities class from the
Connection.getCapabilities()
or Connector.getCapabilities()
method. This class is used by the
Connector Manager to determine what kinds of commands the connector is
capable of executing. A basic implementation of the
ConnectorCapabilities interface is supplied at
BasicConnectorCapabilities. This
capabilities class specifies that the connector does not support any capability. You should extend
this class and override the necessary methods to specify which
capabilities your connector supports.
Note that if your capabilities will remain unchanged for the lifetime
of the connector, you should return them via
Connector.getCapabilities()
since the engine will cache them for reuse by all connections to the
connector. Capabilities returned by the connection will only be cached for the duration of the user request.
The following table lists the capabilities that can be specified in the ConnectorCapabilities class.
Table 3.1. Available Connector Capabilities
Capability |
Requires |
Description |
---|---|---|
SelectDistinct |
Connector can support SELECT DISTINCT in queries. | |
SelectExpression |
Connector can support SELECT of more than just element references. | |
AliasedGroup |
Connector can support groups in the FROM clause that have an alias. | |
SupportedJoinCriteria |
At least one of the join type supports. |
Returns one of the SupportedJoinCriteria enum types: ANY, THETA, EQUI, KEY. KEY is the most restrictive, indicating that the source only supports equi-join criteria specified on the primary key of at least one of the tables in join. |
InnerJoins |
Connector can support inner and cross joins | |
SelfJoins |
AliasedGroups and at least on of the join type supports. |
Connector can support a self join between two aliased versions of the same group. |
OuterJoins |
Connector can support LEFT and RIGHT OUTER JOIN. | |
FullOuterJoins |
Connector can support FULL OUTER JOIN. | |
InlineViews |
AliasedGroup |
Connector can support a named subquery in the FROM clause. |
BetweenCriteria |
Not currently used - between criteria is rewriten as compound comparisions. | |
CompareCriteriaEquals |
Connector can support comparison criteria with the operator "=”. | |
CompareCriteriaOrdered |
Connector can support comparison criteria with the operator ">” or "<". | |
LikeCriteria |
Connector can support LIKE criteria. | |
LikeCriteriaEscapeCharacter |
LikeCriteria |
Connector can support LIKE criteria with an ESCAPE character clause. |
InCriteria |
Connector can support IN predicate criteria. | |
InCriteriaSubquery |
Connector can support IN predicate criteria where values are supplied by a subquery. | |
IsNullCriteria |
Connector can support IS NULL predicate criteria. | |
OrCriteria |
Connector can support the OR logical criteria. | |
NotCriteria |
Connector can support the NOT logical criteria. IMPORTANT: This capability also applies to negation of predicates, such as specifying IS NOT NULL, "<=" (not ">"), ">=" (not "<"), etc. | |
ExistsCriteria |
Connector can support EXISTS predicate criteria. | |
QuantifiedCompareCriteriaAll |
Connector can support a quantified comparison criteria using the ALL quantifier. | |
QuantifiedCompareCriteriaSome |
Connector can support a quantified comparison criteria using the SOME or ANY quantifier. | |
OrderBy |
Connector can support the ORDER BY clause in queries. | |
OrderByUnrelated |
OrderBy |
Connector can support the ORDER BY items that are not directly specified in the select clause. |
GroupBy |
Connector can support an explict GROUP BY clause. | |
Having |
GroupBy |
Connector can support the HAVING clause. |
AggregatesAvg |
Connector can support the AVG aggregate function. | |
AggregatesCount |
Connector can support the COUNT aggregate function. | |
AggregatesCountStar |
Connector can support the COUNT(*) aggregate function. | |
AggregatesDistinct |
At least one of the aggregate functions. |
Connector can support the keyword DISTINCT inside an aggregate function. This keyword indicates that duplicate values within a group of rows will be ignored. |
AggregatesMax |
Connector can support the MAX aggregate function. | |
AggregatesMin |
Connector can support the MIN aggregate function. | |
AggregatesSum |
Connector can support the SUM aggregate function. | |
ScalarSubqueries |
Connector can support the use of a subquery in a scalar context (wherever an expression is valid). | |
CorrelatedSubqueries |
At least one of the subquery pushdown capabilities. |
Connector can support a correlated subquery that refers to an element in the outer query. |
CaseExpressions |
Not currently used - simple case is rewriten as searched case. | |
SearchedCaseExpressions |
Connector can support "searched” CASE expressions anywhere that expressions are accepted. | |
Unions |
Connector support UNION and UNION ALL | |
Intersect |
Connector supports INTERSECT | |
Except |
Connector supports Except | |
SetQueryOrderBy |
Unions, Intersect, or Except |
Connector supports set queries with an ORDER BY |
RowLimit |
Connector can support the limit portion of the limit clause | |
RowOffset |
Connector can support the offset portion of the limit clause | |
FunctionsInGroupBy |
GroupBy |
Not currently used - non-element expressions in the group by create an inline view. |
InsertWithQueryExpression |
Connector supports INSERT statements with values specified by an IQueryCommand. |
Note that any pushdown subquery must itself be compliant with the connector capabilities.
The method ConnectorCapabilities.useAnsiJoin() should return true if the Connector prefers the use of ANSI style join structure for join trees that contain only INNER and CROSS joins.
The method ConnectorCapabilities.requiresCriteria() should return true if the Connector requires criteria for any Query, Update, or Delete. This is a replacement for the model support property "Where All".
The method ConnectorCapabilities.getSupportedFunctions() can be used to specify which scalar functions the connector supports. The set of possible functions is based on the set of functions supported by Teiid. This set can be found in the Reference documentation. If the connector states that it supports a function, it must support all type combinations and overloaded forms of that function.
There are also five standard operators that can also be specified in the supported function list: +, -, *, /, and ||.
The constants interface SourceSystemFunctions contains the string names of all possible built-in pushdown functions. Note that not all system functions appear in this list. This is because some system functions will always be evaluted in Teiid, are simple aliases to other functions, or are rewriten to a more standard expression.
The method ConnectorCapabilities.getMaxInCriteriaSize() can be used to specify the maximum number of values that can be passed in an IN criteria. This is an important constraint as an IN criteria is frequently used to pass criteria between one source and another using a dependent join.
The method ConnectorCapabilities.getMaxFromGroups() can be used to specify the maximum number of FROM Clause groups that can used in a join. -1 indicates there is no limit.
The method ConnectorCapabilities.supportsBatchedUpdates() can be used to indicate that the connector supports executing the IBatchedUpdates command.
The method ConnectorCapabilities.supportsBulkUpdate() can be used to indicate that the connector accepts update commands containg multi valued ILiterals.
Note that if the connector does not support either of these update modes, the query engine will compensate by issuing the updates individually.