Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 369486

Summary: Cancel does not work for getResultSetMetaData()
Product: z_Archived Reporter: ta <tandree>
Component: BIRTAssignee: pshi <pshi>
Status: RESOLVED FIXED QA Contact: Xiaoying Gu <bluesoldier>
Severity: major    
Priority: P3 CC: bluesoldier, tandree
Version: unspecified   
Target Milestone: 4.2.1   
Hardware: PC   
OS: Windows 7   
Whiteboard:

Description ta CLA 2012-01-24 05:08:09 EST
Build Identifier: 3.7.2 RC1

Hello BIRT-Team,

our company is using the BIRT framework as the main reporting engine bundled in our applications.
Usually all our reports are based on OLAP datasources, for that reason we implemented our own ODA dataset and datasource drivers which connect to the Mondrian OLAP project.
Currently we are adding cancel support of all our datasources and run into an implementation issue found in the BIRT framework.

Let me explain our current problem:

Problem:
--------
Generally the ODA dataset flow is usally split into two queries, first: getResultSetMetaData() and second: getResultSet()
The first one delivers informations about the columns of the resultset(names, types, etc.) and the second the rows of the resultset itself.
I noticed that the cancel() method of a ODA dataset will only be invoked for the second getResultSet() query. Currently it is not possible to cancel the getResultSetMetaData() query.

This works fine for SQL-Queries because getting the result set metadata is very fast and getting the resultset takes usually much longer.

But due the nature of our OLAP systems getting the resultsset metadata can take very long. For that reason we need cancel support for the getResultSetMetaData() query.

Solution:
---------
I debugged the cancel support inside the BIRT framework and I think found a good solution. 
I used the BIRT 3.7.2-RC1 source.
Please have a look inside the data engine project at:

package: org.eclipse.birt.data.engine.executor
class: DataSourceQuery
method: prepare()
line: 272

    @SuppressWarnings("restriction")
    public IPreparedDSQuery prepare() throws DataException
    {
        if ( odaStatement != null )
            throw new DataException( ResourceConstants.QUERY_HAS_PREPARED );

        // create and populate a query specification for preparing a statement
        populateQuerySpecification();
        
        odaStatement = dataSource.prepareStatement( queryText, queryType, this.querySpecificaton );
        
        // Add custom properties to odaStatement
        addPropertiesToPreparedStatement( );
        
        // Adds input and output parameter hints to odaStatement.
        // This step must be done before odaStatement.setColumnsProjection()
        // for some jdbc driver need to carry out a query execution before the metadata can be achieved
        // and only when the Parameters are successfully set the query execution can succeed.
        addParameterDefns();
        
        IOdaDataSetDesign design = null;
    	if( session.getDataSetCacheManager( ).getCurrentDataSetDesign( ) instanceof IOdaDataSetDesign )
    		design = (IOdaDataSetDesign)session.getDataSetCacheManager( ).getCurrentDataSetDesign( );
    	
        if ( design != null )
		{
			if ( canAccessResultSetByName( design ) )
			{
				// Ordering is important for the following operations. Column hints
				// should be defined
				// after custom fields are declared (since hints may be given to
				// those custom fields).
				// Column projection comes last because it needs hints and
				// custom
				// column information
				addCustomFields( design.getPrimaryResultSetName( ), odaStatement );
				addColumnHints( design.getPrimaryResultSetName( ), odaStatement );

				if ( this.projectedFields != null )
					odaStatement.setColumnsProjection( design.getPrimaryResultSetName( ), this.projectedFields );
			}
			else if( canAccessResultSetByNumber( design ) )
			{
				addCustomFields( design.getPrimaryResultSetNumber( ), odaStatement );
				addColumnHints( design.getPrimaryResultSetNumber( ), odaStatement );

				if ( this.projectedFields != null )
					odaStatement.setColumnsProjection( design.getPrimaryResultSetNumber( ), this.projectedFields );
			}
			else
			{
				//NEW FIX STARTS HERE
	        	ICancellable queryCanceller = new OdaQueryCanceller( odaStatement, session.getStopSign() );
	        	this.session.getCancelManager( ).register( queryCanceller );
				prepareColumns( );
	    		this.session.getCancelManager( ).deregister( queryCanceller );
				//NEW FIX ENDS HERE
			}
		}else
		{
				//NEW FIX STARTS HERE
        	ICancellable queryCanceller = new OdaQueryCanceller( odaStatement, session.getStopSign() );
        	this.session.getCancelManager( ).register( queryCanceller );
			prepareColumns( );
    		this.session.getCancelManager( ).deregister( queryCanceller );
			//NEW FIX ENDS HERE
		}
        
		//Here the "max rows" means the max number of rows that can fetch from data source.
		odaStatement.setMaxRows( this.getRowFetchLimit( ) );
		
        // If ODA can provide result metadata, get it now
        try
        {
        	ICancellable queryCanceller = new OdaQueryCanceller( odaStatement, session.getStopSign() );
        	this.session.getCancelManager( ).register( queryCanceller );
        	
        	if( !session.getStopSign().isStopped() )
        		resultMetadata = getMetaData( (IOdaDataSetDesign)session.getDataSetCacheManager( ).getCurrentDataSetDesign( ), odaStatement );
        	
        	if ( queryCanceller.collectException( ) != null )
    		{
    			if ( !( queryCanceller.collectException( ).getCause( ) instanceof UnsupportedOperationException ) )
    				throw queryCanceller.collectException( );
    		}
    		
    		this.session.getCancelManager( ).deregister( queryCanceller );

        }
        catch ( DataException e )
        {
            // Assume metadata not available at prepare time; ignore the exception
        	resultMetadata = null;
        }
        
        return this;
    }

	
Description:
------------

Please refer to the //NEW FIX comments. As you can see I wrapped the prepareColumns() method with your queryCanceller pattern.
That's all. We are currently using this fix and now our cancellation work fine in the getRestultSetMetaData() phase.


It would be great if you could add this fix to the next BIRT 3.7.2 release.






Reproducible: Always

Steps to Reproduce:
Please see "Details".
Comment 1 pshi CLA 2012-08-21 02:14:23 EDT
Fixed