void derivedTableOptimization(SCSEP& csep)
{
    // @bug5634. replace the unused column with ConstantColumn from derived table column list,
    // ExeMgr will not project ConstantColumn. Only count for local derived column.
    // subquery may carry main query derived table list for column reference, those
    // derived tables are not checked for optimization in this scope.
    CalpontSelectExecutionPlan::SelectList derivedTbList = csep->derivedTableList();

    // @bug6156. Skip horizontal optimization for no table union.
    bool horizontalOptimization = true;

    for (uint i = 0; i < derivedTbList.size(); i++)
    {
        CalpontSelectExecutionPlan* plan = dynamic_cast<CalpontSelectExecutionPlan*>(derivedTbList[i].get());
        CalpontSelectExecutionPlan::ReturnedColumnList cols = plan->returnedCols();
        vector<CalpontSelectExecutionPlan::ReturnedColumnList> unionColVec;

        // only do vertical optimization for union all
        // @bug6134. Also skip the vertical optimization for select distinct
        // because all columns need to be projected to check the distinctness.
        bool verticalOptimization = false;

        if (plan->distinctUnionNum() == 0 && !plan->distinct())
        {
            verticalOptimization = true;

            for (uint j = 0; j < plan->unionVec().size(); j++)
            {
                unionColVec.push_back(
                    dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols());
            }
        }

        if (plan->tableList().empty())
            horizontalOptimization = false;

        for (uint j = 0; j < plan->unionVec().size(); j++)
        {
            if (dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get())->tableList().empty())
            {
                horizontalOptimization = false;
                break;
            }
        }

        if (verticalOptimization)
        {
            int64_t val = 1;

            for (uint i = 0; i < cols.size(); i++)
            {
                //if (cols[i]->derivedTable().empty())
                if (cols[i]->refCount() == 0)
                {
                    if (cols[i]->derivedRefCol())
                        cols[i]->derivedRefCol()->decRefCount();

                    cols[i].reset(new ConstantColumn(val));

                    for (uint j = 0; j < unionColVec.size(); j++)
                        unionColVec[j][i].reset(new ConstantColumn(val));
                }
            }

            // set back
            plan->returnedCols(cols);

            for (uint j = 0; j < unionColVec.size(); j++)
                dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols(unionColVec[j]);
        }
    }

    /*
     * @bug5635. Move filters that only belongs to a derived table to inside the derived table.
     * 1. parse tree walk to populate derivedTableFilterMap and set null candidate on the tree.
     * 2. remove the null filters
     * 3. and the filters of derivedTableFilterMap and append to the WHERE filter of the derived table
     *
     * Note:
     * 1. Subquery filters is ignored because derived table can not be in subquery
     * 2. While walking tree, whenever a single derive simplefilter is encountered,
     * this filter is pushed to the corresponding stack
     * 2. Whenever an OR operator is encountered, all the filter stack of
     * that OR involving derived table are emptied and null candidate of each
     * stacked filter needs to be reset (not null)
     */
    ParseTree* pt = csep->filters();
    map<string, ParseTree*> derivedTbFilterMap;

    if (horizontalOptimization && pt)
    {
        pt->walk(setDerivedTable);
        setDerivedFilter(pt, derivedTbFilterMap, derivedTbList);
        csep->filters(pt);
    }

    // AND the filters of individual stack to the derived table filter tree
    // @todo union filters.
    // @todo outer join complication
    map<string, ParseTree*>::iterator mapIt;

    for (uint i = 0; i < derivedTbList.size(); i++)
    {
        CalpontSelectExecutionPlan* plan = dynamic_cast<CalpontSelectExecutionPlan*>(derivedTbList[i].get());
        CalpontSelectExecutionPlan::ReturnedColumnList derivedColList = plan->returnedCols();
        mapIt = derivedTbFilterMap.find(plan->derivedTbAlias());

        if (mapIt != derivedTbFilterMap.end())
        {
            // replace all derived column of this filter with real column from
            // derived table projection list.
            ParseTree* mainFilter = new ParseTree();
            mainFilter->copyTree(*(mapIt->second));
            replaceRefCol(mainFilter, derivedColList);
            ParseTree* derivedFilter = plan->filters();

            if (derivedFilter)
            {
                LogicOperator* op = new LogicOperator("and");
                ParseTree* filter = new ParseTree(op);
                filter->left(derivedFilter);
                filter->right(mainFilter);
                plan->filters(filter);
            }
            else
            {
                plan->filters(mainFilter);
            }

            // union filter handling
            for (uint j = 0; j < plan->unionVec().size(); j++)
            {
                CalpontSelectExecutionPlan* unionPlan =
                    dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get());
                CalpontSelectExecutionPlan::ReturnedColumnList unionColList = unionPlan->returnedCols();
                ParseTree* mainFilterForUnion = new ParseTree();
                mainFilterForUnion->copyTree(*(mapIt->second));
                replaceRefCol(mainFilterForUnion, unionColList);
                ParseTree* unionFilter = unionPlan->filters();

                if (unionFilter)
                {
                    LogicOperator* op = new LogicOperator("and");
                    ParseTree* filter = new ParseTree(op);
                    filter->left(unionFilter);
                    filter->right(mainFilterForUnion);
                    unionPlan->filters(filter);
                }
                else
                {
                    unionPlan->filters(mainFilterForUnion);
                }
            }
        }
    }

    // clean derivedTbFilterMap because all the filters are copied
    for ( mapIt = derivedTbFilterMap.begin(); mapIt != derivedTbFilterMap.end(); ++mapIt )
        delete (*mapIt).second;

    // recursively process the nested derived table
    for (uint i = 0; i < csep->subSelectList().size(); i++)
    {
        SCSEP subselect(boost::dynamic_pointer_cast<CalpontSelectExecutionPlan>(csep->subSelectList()[i]));
        derivedTableOptimization(subselect);
    }
}
ostream &operator<< (ostream &output, const CalpontSelectExecutionPlan &cep)
{
	output << ">SELECT " ;
	if (cep.distinct())
		output << "DISTINCT ";
	output << "limit: " << cep.limitStart() << " - " << cep.limitNum() << endl; 
	
	switch (cep.location())
	{
		case CalpontSelectExecutionPlan::MAIN:
	    output << "MAIN" << endl;
	    break;
    case CalpontSelectExecutionPlan::FROM:
        output << "FROM" << endl;
        break;
    case CalpontSelectExecutionPlan::WHERE:
        output << "WHERE" << endl;
        break;
    case CalpontSelectExecutionPlan::HAVING:
        output << "HAVING" << endl;
        break;
   }	    
	
	// Returned Column
	CalpontSelectExecutionPlan::ReturnedColumnList retCols = cep.returnedCols();	
	output << ">>Returned Columns" << endl;
	uint seq = 0;
	for (unsigned int i = 0; i < retCols.size(); i++)
	{
		output << *retCols[i] << endl;
		if (retCols[i]->colSource() & SELECT_SUB)
		{
			output << "select sub -- " << endl;
			CalpontSelectExecutionPlan *plan = dynamic_cast<CalpontSelectExecutionPlan*>(cep.fSelectSubList[seq++].get());
			if (plan)
				output << "{" << *plan << "}" << endl; 
		}
	}
	
	// From Clause
	CalpontSelectExecutionPlan::TableList tables = cep.tableList();	
	output << ">>From Tables" << endl;
	seq = 0;
	for (unsigned int i = 0; i < tables.size(); i++)
	{
		// derived table
		if (tables[i].schema.length() == 0 && tables[i].table.length() == 0)
		{
			output << "derived table - " << tables[i].alias << endl;
			CalpontSelectExecutionPlan *plan = dynamic_cast<CalpontSelectExecutionPlan*>(cep.fDerivedTableList[seq++].get());
			if (plan)
				output << "{" << *plan << "}" << endl; 
		}
		else
		{
			output << tables[i] << endl;
		}
	}
	
	// Filters
	output << ">>Filters" << endl;
  if (cep.filters() != 0)
  	cep.filters()->walk (ParseTree::print, output);
  else
  	output << "empty filter tree" << endl;
    
	// Group by columns
	CalpontSelectExecutionPlan::GroupByColumnList groupByCols = cep.groupByCols();
	if (groupByCols.size() > 0)
	{
  	output << ">>Group By Columns" << endl;
  	for (unsigned int i = 0; i < groupByCols.size(); i++)
    	output << *groupByCols[i] << endl;
	}
    
	// Having
	if (cep.having() != 0)
	{
		output << ">>Having" << endl;
		cep.having()->walk (ParseTree::print, output);
	}
    
	// Order by columns
	CalpontSelectExecutionPlan::OrderByColumnList orderByCols = cep.orderByCols();
	if (orderByCols.size() > 0)
	{
		output << ">>Order By Columns" << endl;
		for (unsigned int i = 0; i < orderByCols.size(); i++)
			output << *orderByCols[i] << endl;
	}   
	output << "SessionID: " << cep.fSessionID << endl;
	output << "TxnID: " << cep.fTxnID << endl;
	output << "VerID: " << cep.fVerID << endl;
	output << "TraceFlags: " << cep.fTraceFlags << endl;
	output << "StatementID: " << cep.fStatementID << endl;
	output << "DistUnionNum: " << (int)cep.fDistinctUnionNum << endl;
	output << "Limit: " << cep.fLimitStart << " - " << cep.fLimitNum << endl;
	output << "String table threshold: " << cep.fStringTableThreshold << endl;
	  
	output << "--- Column Map ---" << endl;
	CalpontSelectExecutionPlan::ColumnMap::const_iterator iter;
	for (iter = cep.columnMap().begin(); iter != cep.columnMap().end(); iter++)
		output << (*iter).first << " : " << (*iter).second << endl;
	
	return output;
}