aggr.func = expr.getAggregation( );
aggr.aggregation = expr.getAggregation( );
		private AggrExprInfo newAggrExprInfo( AggregateExpression expr,				int currentGroupLevel, boolean afterGroup, boolean isDetailedRow, Context cx )				throws DataException		{			AggrExprInfo aggr = new AggrExprInfo( );			assert expr != null;			assert currentGroupLevel >= 0;			aggr.func = expr.getAggregation( );			aggr.afterGroup = afterGroup;			List exprArgs = expr.getArguments( );			// Find out how many fixed arguments this aggregate function takes			// Optional filter and group arguments follow the fixed arguments			int nFixedArgs = aggr.func.getParameterDefn( ).length;			// Verify that the expression has the right # of arguments			int nArgs = exprArgs.size( );			if ( nArgs < nFixedArgs || nArgs > nFixedArgs + 2 )			{				DataException e = new DataException( ResourceConstants.INVALID_AGGR_PARAMETER,						aggr.func.getName( ) );				logger.logp( Level.FINE,						AggregateTable.class.getName( ),						"newAggrExprInfo",						"Wrong number of arguments to aggregate function",						e );				throw e;			}						// Determine grouping level for this aggregate			// Look at the group level argument. If it is not present, or is null, the group level			// is the same group in which the aggregate expression is defined.			aggr.groupLevel = currentGroupLevel;			if ( nArgs == nFixedArgs + 2 )			{				CompiledExpression groupExpr = (CompiledExpression) exprArgs.get( nArgs - 1 );				if ( !( groupExpr instanceof ConstantExpression ) )				{					DataException e = new DataException( ResourceConstants.INVALID_AGGR_GROUP_EXPRESSION,							aggr.func.getName( ) );					logger.logp( Level.FINE,							AggregateTable.class.getName( ),							"newAggrExprInfo",							"Invalid grouping expression for aggregate function",							e );					throw e;				}				// Note that we use the data engine's shared scope for this				// evaluation. Group expression				// is not expected to depend on any query execution. In fact it				// should just be a constant				// expression most of the case				Object groupLevelObj = groupExpr.evaluate( cx,						runStates == BASE_QUERY ? cx.initStandardObjects( )								: scope );				if ( groupLevelObj == null )				{					// null argument; use default level				}				else if ( groupLevelObj instanceof String )				{					int innerMostGroup = 0;					if ( runStates == PREPARED_QUERY )					{						innerMostGroup = groupCount;					}					else					{						innerMostGroup = baseQuery.getGrouping( ) != null								? baseQuery.getGrouping( ).length : 0;					}						int groupLevel = AggregationConstantsUtil.getGroupLevel( (String)groupLevelObj, currentGroupLevel,innerMostGroup, isDetailedRow);					//When the groupLevelObj can be recognized, it will return a non-negative value.Else return -1.					if ( groupLevel != -1 )					{						aggr.groupLevel = groupLevel;					}					else					{						aggr.groupLevel = ( runStates == BASE_QUERY )								? getGroupIndex( groupLevelObj.toString( ) )								: getGroupIndexFromPreparedQuery( (String) groupLevelObj );					}				}				else if ( groupLevelObj instanceof Number )				{					int offset = ( (Number) groupLevelObj ).intValue( );					if ( offset < 0 )						aggr.groupLevel = currentGroupLevel + offset;					else						aggr.groupLevel = offset;				}				if ( aggr.groupLevel < 0						|| aggr.groupLevel > ( runStates == BASE_QUERY								? ( baseQuery.getGrouping( ) == null ? 0										: baseQuery.getGrouping( ).length )								: groupCount ) )				{					DataException e = new DataException( ResourceConstants.INVALID_GROUP_LEVEL,							aggr.func.getName( ) );					logger.logp( Level.FINE,							AggregateTable.class.getName( ),							"newAggrExprInfo",							"Invalid grouping level for aggregate function",							e );					throw e;				}			}			// Extract filter parameter			if ( nArgs > nFixedArgs )			{				aggr.filter = (CompiledExpression) exprArgs.get( nFixedArgs );				// If filter expression is a constant "null", ignore it				if ( aggr.filter instanceof ConstantExpression						&& ( (ConstantExpression) aggr.filter ).getValue( ) == null )				{					aggr.filter = null;				}			}			aggr.args = new CompiledExpression[nFixedArgs];			if ( nFixedArgs > 0 )			{				exprArgs.subList( 0, nFixedArgs ).toArray( aggr.args );			}			return aggr;		}