Simba Technologies
Simba Technologies

SimbaEngine X SDK 10.1.3
Developing Drivers for Data Stores Without SQL

Pass-Down Operation Handlers

After parsing a SQL query and generating the AE-Tree, the Simba SQLEngine does analysis to identify the following types of operations that a data store may be able to handle in an optimized way:

  • Filter
  • Join
  • Aggregation
  • Projection
  • Union
  • Distinct
  • Top
  • Sort

After identifying these operations, the Simba SQLEngine checks if the operation handlers for each operation exist and if passdown is enabled. If so, the SQLEngine attempts to pass down details of the operation to the DSII so that it may fully or partially perform that operation. If it can’t perform the operation, it will fall back to being performed by the Simba SQLEngine.

The operation handlers are constructed by a factory class, DSIExtOperationHandlerFactory, which you must subclass to construct your own handler classes. The factory class itself is to be constructed by overriding the DSIExtSqlDataEngine::CreateOperationHandlerFactory method. Under the Java Simba SQLEngine, the equivalent method is SqlDataEngine.createOperationHandlerFactory(). Note that a subclass of DSIExtSqlDataEngine (SqlDataEnginefor Java) is required since CQE may utilize the Simba SQLEngine. See Implementation.

More generally, any driver which uses the Simba SQLEngine for execution must subclass DSIExtSqlDataEngine, or SqlDataEngine if building a JDBC driver.


If you don’t want to support pass downs, for example if you don’t plan to have pass down handler implementations, then return nullin the CreateOperationHandlerFactory override in your DSIExtSqlDataEngineor SqlDataEngine derived class. The sample takes this a step further by providing the ability to enable or disable pass down support at runtime by setting PASSDOWN=1 or PASSDOWN=0 respectively in the driver’s registry settings or in the DSN connection string.

In the CodeBase example, the CBEngine class constructs a CBOperationHandlerFactory:

AutoPtr<DSIExtOperationHandlerFactory> CBDataEngine::CreateOperationHandlerFactory(){

return AutoPtr<DSIExtOperationHandlerFactory>(new CBOperationHandlerFactory(m_Settings));


The CBOperationHandlerFactory then returns the appropriate subclassed handlers via the respective methods (e.g. CreateFilterHandler(), CreateJoinHandler(), etc.) which are invoked by Simba SQLEngine.

Each handler class defines and implements some or all of the following methods which will be invoked by the Simba SQLEngine during CQE:

  • Passdown()
  • This method is defined and implemented for all handlers because it performs the pass down logic. Depending on the type of handler, this method may return a scalar (e.g. the number of rows found in a count operation), boolean (e.g. indicating if an expression can be handled), or a result set (e.g. an aggregated result set).

  • TakeResult()
  • Returns a result set generated by the DSII. This method is defined and implemented only for Join, Filter, and Sort handlers and thus used in cases where Passdown() indicates a status result of whether the expression could be handled either fully, partially, or not at all. In these cases, the operation handling and result generation are performed via two methods (Passdown() and TakeResult() respectively), as opposed to just using the Passdown() method. This allows the Join, Filter, and Sort operations to indicate to the Simba SQLEngine whether the DSII will be able to handle the operation (i.e. supports it), and if so, whether it can handle it fully or partially.

  • CanHandleMoreClauses()
  • This method is defined and implemented in the handler used for Joins and Filters and is invoked by the Simba SQLEngine so that the handler can signal whether or not any further passdowns of expressions should be made to the handler. For example, a Join handler may determine that predicates cannot be handled by the DSII and thus no further pass downs should be sent to the handler.

More information about each handler and their usage of these methods is provided next.

Combining Pass-Downs

For complex queries involving multiple tables, filters, joins, or aggregations, there may be many operations that can be passed down. However, to pass down an operation higher in the AE Tree, all operations below that node must have been fully passed down. This limitation is required so that when constructing the new operation handler, the base tables passed to the factory are always tables either opened by the data engine or constructed by earlier operation handlers. Therefore, if a table filter could not be passed down, the engine cannot pass down a join higher up in the AE-Tree involving the result of the table filter because the engine must first process the filter itself before the join can be performed.

Pre Optimization Analysis of the AE-Tree

If optimizations cannot be performed within pass down handlers, the DSII has the option to analyze an AE Tree after it has been generated from the query, and to optimize or alter it prior to the three stop optimization process. Doing this can completely change the query and is only recommended as a last resort if the optimizations cannot be performed elsewhere.

This can be accomplished by overriding theDSIExtSqlDataEngine::CreateQueryExecutorto intercept the AEStatements before calling the base class function to finish constructing the query executor:

DSIExtQueryExecutor* CustomerDSIISqlDataEngine::CreateQueryExecutor(

AutoPtr<AEStatements> in_aeStatements)


// Analyze and alter the AE-Trees found in in_aeStatements

return DSIExtSqlDataEngine::CreateQueryExecutor(in_aeStatements);


How to analyze the tree, and what changes to make, is up to the DSII implementer according to whatever circumstances require it so no example can be given here. Instead, refer to the API reference guide for full details on the structure of the AE-Tree.


Related Links

Overview of Collaborative Query Execution

Algebraic Expression Tree and Optimization