Executing Commands
Execution Modes
The Teiid Spring Boot query engine uses the "ExecutionFactory" class to obtain the "Execution" interface for the command it is executing. The actual queries themselves are sent to translators in the form of a set of objects, which are further described in Command Language. Refer to Command Language. Translators are allowed to support any subset of the available execution modes.
Execution Interface | Command interface(s) | Description |
---|---|---|
|
|
A query corresponding to a SQL SELECT or set query statement. |
|
|
An insert, update, or delete, corresponding to a SQL INSERT, UPDATE, or DELETE command |
|
|
A procedure execution that may return a result set and/or output values. |
Types of Execution Modes
All of the execution interfaces extend the base Execution
interface that defines how executions are cancelled and closed. ProcedureExecution also extends ResultSetExecution, since procedures may also return resultsets.
ExecutionContext
The org.teiid.translator.ExecutionContext
provides a considerable amount of information related to the current execution. An ExecutionContext
instance is made available to each Execution
. Specific usage is highlighted in this guide where applicable, but you may use any informational getter method as desired. Example usage would include calling ExecutionContext.getRequestId()
, ExecutionContext.getSession()
, etc. for logging purposes.
CommandContext
A org.teiid.CommandContext
is available via the ExecutionContext.getCommandContext()
method. The CommandContext contains information about the current user query, including the VDB
, the ability to add client warnings - addWarning
, or handle generated keys - isReturnAutoGeneratedKeys
, returnGeneratedKeys
, and getGeneratedKeys
.
Generated Keys
To see if the user query expects generated keys to be returned, consult the CommandContext.isReturnAutoGeneratedKeys()
method. If you wish to return generated keys, you must first create a GeneratedKeys
instance to hold the keys with the returnGeneratedKeys
method passing the column names and types of the key columns. Only one GeneratedKeys
may be associated with the CommandContext
at any given time.
Source Hints
The Teiid Spring Boot source meta-hint is used to provide hints directly to source executions via user or transformation queries. See the reference for more on source hints. If specified and applicable, the general and source specific hint will be supplied via the ExecutionContext methods getGeneralHint
and getSourceHint
. See the source for the OracleExecutionFactory
for an example of how this source hint information can be utilized.
ResultSetExecution
Typically most commands executed against translators are QueryExpression. While the command is being executed, the translator provides results via the ResultSetExecution’s "next" method. The "next" method should return null to indicate the end of results. Note: the expected batch size can be obtained from the ExecutionContext.getBatchSize()
method and used as a hint in fetching results from the EIS.
Update Execution
Each execution returns the update count(s) expected by the update command. If possible BatchedUpdates should be executed atomically. The ExecutionContext.isTransactional()
method can be used to determine if the execution is already under a transaction.
Procedure Execution
Procedure commands correspond to the execution of a stored procedure or some other functional construct. A procedure takes zero or more input values and can return a result set and zero or more output values. Examples of procedure execution would be a stored procedure in a relational database or a call to a web service.
If a result set is expected when a procedure is executed, all rows from it will be retrieved via the ResultSetExecution interface first. Then, if any output values are expected, they will be retrieved via the getOutputParameterValues() method.
Asynchronous Executions
In some scenarios, a translator needs to execute asynchronously and allow the executing thread to perform other work. To allow asynchronous execution, you should throw a DataNotAvailableExecption
during a retrieval method, rather than explicitly waiting or sleeping for the results. The DataNotAvailableException
may take a delay parameter or a Date
in its constructor to indicate when to poll next for results. Any non-negative delay value indicates the time in milliseconds until the next polling should be performed. The DataNotAvailableException.NO_POLLING
exception (or any DataNotAvailableException with a negative delay) can be thrown to indicate that the execution will call ExecutionContext.dataAvailable()
to indicate processing should resume.
Note
|
A DataNotAvailableException should not be thrown by the execute method, as that can result in the execute method being called multiple times.
|
Note
|
Since the execution and the associated connection are not closed until the work has completed, care should be taken if using asynchronous executions that hold a lot of state. |
A positive retry delay is not a guarantee of when the translator will be polled next. If the DataNotAvailableException
is consumed while the engine thinks more work can be performed or there are other shorter delays issued from other translators, then the plan may be re-queued earlier than expected. You should simply rethrow a DataNotAvailableException
if your execution is not yet ready. Alternatively the DataNotAvailableException
may be marked as strict, which does provide a guarantee that the Execution
will not be called until the delay has expired or the given Date
has been reached. Using the Date
constructor makes the DataNotAvailableException
automatically strict. Due to engine thread pool contention, platform time resolution, etc. a strict DataNotAvailableException
is not a real-time guarantee of when the next poll for results will occur, only that it will not occur before then.
Note
|
If your ExecutionFactory returns only asynch executions that perform minimal work, then consider having ExecutionFactory.isForkable return false so that the engine knows not to spawn a separate thread for accessing your Execution .
|
Reusable Executions
A translator may return instances of ReusableExecutions
for the expected Execution objects. There can be one ReusableExecution
per query executing node in the processing plan. The lifecycle of a ReusableExecution
is different that a normal Execution
. After a normal creation/execute/close cycle the ReusableExecution.reset
is called for the next execution cycle. This may occur indefinitely depending on how many times a processing node executes its query. The behavior of the close
method is no different than a regular Execution
, it may not be called until the end of the statement if lobs are detected and any connection associated with the Execution
will also be closed. When the user command is finished, the ReusableExecution.dispose()
method will be called.
In general ReusableExecutions
are most useful for continuous query
execution and will also make use of the
ExecutionCotext.dataAvailable()
method for Asynchronous Executions. See the Client Developer’s Guide for executing continuous statements. In continuous mode the user query will be continuously re-executed. A ReusableExecution
allows the same Execution
object to be associated with the processing plan for a given processing node for the lifetime of the user query. This can simplify asynch resource management, such as establishing queue listeners. Returning a null result from the next()
method ReusableExecution
just as with normal Executions
indicates that the current pushdown command results have ended. Once the reset()
method has been called, the next set of results should be returned again terminated with a null result.
Bulk Execution
Non batched Insert, Update, Delete
commands may have multi-valued Parameter
objects if the capabilities shows support for BulkUpdate. Commands with multi-valued Parameters
represent multiple executions of the same command with different values. As with BatchedUpdates, bulk operations should be executed atomically if possible.
Command Completion
All normal command executions end with the calling of close()
on the Execution object. Your implementation of this method should do the appropriate clean-up work for all state created in the Execution object.
Command Cancellation
Commands submitted to Teiid Spring Boot may be aborted in several scenarios:
-
Client cancellation via the JDBC API (or other client APIs)
-
Administrative cancellation
-
Clean-up during session termination
-
Clean-up if a query fails during processing Unlike the other execution methods, which are handled in a single-threaded manner, calls to cancel happen asynchronously with respect to the execution thread.
Your connector implementation may choose to do nothing in response to this cancellation message. In this instance, Teiid Spring Boot will call close() on the execution object after current processing has completed. Implementing the cancel() method allows for faster termination of queries being processed and may allow the underlying data source to terminate its operations faster as well.