Bug 453194 - Endless recursion with aggregate expressions
Summary: Endless recursion with aggregate expressions
Status: NEW
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: BIRT (show other bugs)
Version: 4.2.1   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Birt-ReportEngine-inbox@eclipse.org CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-11-25 08:16 EST by Henning von Bargen CLA
Modified: 2014-11-25 08:16 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Henning von Bargen CLA 2014-11-25 08:16:44 EST
Note: The following example is nonsense (the actual report where the problem was noticed is too complex to explain or attach here).

Consider a master-detail report with an outer List DEPT and an inner Table EMP, bound to corresponding DataSets DEPT resp EMP.

(Imagine Oracle's DEPT/EMP demo database)

The Table EMP contains a binding named DEPTNO bound to the expression row._outer["DEPTNO"] (so the value is taken from the outer List).

The Table EMP also contains an aggregate binding named Count with an aggregate function COUNT and the expression row["DEPTNO"].

The visibility expression for Table EMP is !row["Count"], e.g. we want to show the table iff row["Count"] is empty/zero.

Again: This is a non-sensical report, just to demonstrate the error.

This report will run into an endless recursion and finally end with a StackOverflowError!

The traceback will look like this:
Invalid javascript expression: row._outer["DEPTNO"]
or StackOverflowError
...
	at org.eclipse.birt.data.engine.impl.ServiceForQueryResults$EventHandler.popAggrRefFromScriptExpr(ServiceForQueryResults.java:872)
	at org.eclipse.birt.data.engine.impl.ServiceForQueryResults$EventHandler.popAggrRefFromBaseExpr(ServiceForQueryResults.java:801)
	at org.eclipse.birt.data.engine.impl.ServiceForQueryResults$EventHandler.popAggrRefFromScriptExpr(ServiceForQueryResults.java:872)
	at org.eclipse.birt.data.engine.impl.ServiceForQueryResults$EventHandler.popAggrRefFromBaseExpr(ServiceForQueryResults.java:801)
	at org.eclipse.birt.data.engine.impl.ServiceForQueryResults$EventHandler.popAggrRefFromScriptExpr(ServiceForQueryResults.java:872)
	at org.eclipse.birt.data.engine.impl.ServiceForQueryResults$EventHandler.popAggrRefFromBaseExpr(ServiceForQueryResults.java:801)
and so on.

The reason for this seems to be this code in org.eclipse.birt.data.engine.impl/ServiceForQueryResults:

        private boolean popAggrRefFromScriptExpr( Set aggrReferences, IScriptExpression expr, Map aggrMap )
                throws DataException
        {
            try
            {
                List usedRowReferences = ExpressionUtil.extractColumnExpressions( expr.getText( ) );
                boolean result = this.hasDataSetRowReference( expr );
                for ( int i = 0; i < usedRowReferences.size( ); i++ )
                {
                    Object o = aggrMap.get( ( (IColumnBinding) usedRowReferences.get( i ) ).getResultSetColumnName( ) );
                    if ( o != null )
                    {
                        aggrReferences.add( o );
                    }else
                    {
                        result = result || popAggrRefFromBaseExpr( aggrReferences,
                                this.getBinding( ( (IColumnBinding) usedRowReferences.get( i ) ).getResultSetColumnName( ) )
                                        .getExpression( ),
                                aggrMap );
                    }
                }
                return result;
            }
            catch ( BirtException be )
            {
                throw DataException.wrap( be );
            }
        }

Since our Aggregate function does not count a column from the dataset (instead, it counts something from _outer indirectly), o is null and popAggrRefFromBaseExpr is called which in turn calls popAggrRefFromScriptExpr and so on forever.

I propose to either explicitly support this case or to check this at design time and show an appropriate error message.