Connecting to a Data Source Using an IDD

Step 4: Processing K2-mode queries

To handle queries received as K2 abstract syntax trees, your connection class must implement its executeK2Query and getK2QueryResultType methods. These are called by the execution engine when it receives a query which contains one of the entry point variables you exported through getSourceMetaData. If you did not export any variables (that is, if your getSourceMetaData returns null), your executeK2Query and getK2QueryResultType methods should never be called, and you should implement them to throw an UnsupportedQueryException.

executeK2Query is called with a K2 query and an environment in which it should be evaluated. How your driver handles sending the K2 query to the data source is up to you. A common technique is to convert the abstract syntax tree into a query string in the native language of the data source. The connection object traverses the tree, finding instances of your entry points, and converting them to queries over the data source. Once you have converted the K2 query into a native query string, your connection object can then call its own executeNativeQuery method to send the string to the data source and return the result.

However, the abstract syntax tree may contain nodes in addition to the entry point variables, nodes which were "pushed" down to the driver by the optimizer. Your driver has two options for dealing with these nodes. The simplest is basically to ignore them. Process the native queries you generated from the entry point variables, take the results (now expressed as K2 data types), and use them to replace the corresponding nodes in the query. Now K2 should be able to fully evaluate the new query, so simply call the its evaluate method and return the result.

Note that handling things in this way defeats the purpose of pushing nodes down to the driver. The reason they are pushed this far is so that the driver can push them even farther, down to the data source itself. The second way of handling these extra nodes is to rewrite the native queries generated from the entry point variables to incorporate some of the nodes. For example, suppose the variable Table1 translates to "select * from Table1", and the variable node is wrapped in a K2.absyn.expns.absynAggExt which applies a K2.absyn.expns.absynProj to each element, projecting out the value of the field name. Your connection object can replace the entire absynAggExt with the results of the query "select name from Table1". In this way, we have "pushed" the selection down to the data source, thereby improving the efficiency of the query.

Like getNativeQueryResultType, a future enhancement of the execution engine will call getK2QueryResultType with queries and expect it to return the type of the result that would be returned by executeK2Query, without actually executing the query.

Two other abstract methods which your connection object needs to implement are supportsSemijoins and executeSemijoin. An extension of OQL allows a semijoin statement to appear in an OQL query, which will call executeSemijoin to perform a semijoin (a join between a local collection and a collection generated from a K2-mode query). If your connection object implements supportsSemijoins to return false, executeSemijoin should never be called, and you can implement it to throw an UnsupportedQueryException.

The only other thing your IDD must do is report its current status.


[Tech Docs Index]