//--------------------------------------------------------------------------//
//	CRUUnAuditRefreshTaskExecutor::ComposeIndexesSql()
//
//--------------------------------------------------------------------------//
void CRUUnAuditRefreshTaskExecutor::ComposeIndexesSql()
{
	
	const CDDIndexList &indexList = GetRootMV().GetIndexList();

        if( NULL == pUnAuditPopIndexdynamicContainer_ )
        {
    	  pUnAuditPopIndexdynamicContainer_ = 
		new CRUSQLDynamicStatementContainer(numOfIndexes_);
        }

        if( NULL == pUnAuditAvailableIndeXdynamicContainer_ )
        {
	  pUnAuditAvailableIndeXdynamicContainer_ =
		new CRUSQLDynamicStatementContainer(numOfIndexes_);
        }

        if( NULL == pUnAuditUnavailableIndeXdynamicContainer_ )
        {
	  pUnAuditUnavailableIndeXdynamicContainer_ = 
		new CRUSQLDynamicStatementContainer(numOfIndexes_);
        }

	DSListPosition pos = indexList.GetHeadPosition();
	
	for (Int32 i=0;NULL != pos;i++)
	{
		CDDIndex *pddIndex = indexList.GetNext(pos);
	
		CDSString popIdxRqst;
		GetRootMV().GetPopIndexCatApiRequestText(popIdxRqst, pddIndex);
#pragma nowarn(1506)   // warning elimination 
		pUnAuditPopIndexdynamicContainer_->SetStatementText(i, popIdxRqst);
#pragma warn(1506)  // warning elimination 

		CDSString availablepopIdxRqst;
		GetRootMV().GetUpdateIndexStatusCatApiRequestText(availablepopIdxRqst, 
														  TRUE, /*available*/
														  pddIndex);
#pragma nowarn(1506)   // warning elimination 
		pUnAuditAvailableIndeXdynamicContainer_->SetStatementText(i, availablepopIdxRqst);
#pragma warn(1506)  // warning elimination 

		CDSString unavailableIdxRqst; 
		GetRootMV().GetUpdateIndexStatusCatApiRequestText(unavailableIdxRqst, 
														  FALSE, /*unavailable*/
														  pddIndex);
#pragma nowarn(1506)   // warning elimination 
		pUnAuditUnavailableIndeXdynamicContainer_->SetStatementText(i, unavailableIdxRqst);
#pragma warn(1506)  // warning elimination 
	}
}
void CRURefreshTaskExecutor::UpdateRootMVStatistics(TInt32 currDuration)
{
	CRURefreshTask &task = *GetRefreshTask();
	if (FALSE == task.NeedToExecuteInternalRefresh())
	{
		return;
	}

	CRUDeltaDefList &deltaDefList = task.GetDeltaDefList();

	TInt32 prevDuration, nextDuration;
	CRUMV &rootMV = GetRootMV();

	if (TRUE == IsRecompute())
	{
		prevDuration = rootMV.GetRecomputeDurationEstimate();
		nextDuration = EvaluateHeuristic(currDuration, prevDuration);
		rootMV.SetRecomputeDurationEstimate(nextDuration);
		return;
	}

	switch(deltaDefList.GetCount())
	{
		case 0:
		{
			// This cannot happen 
			// (NeedToExecuteInternalRefresh() must have returned FALSE).
			RUASSERT(FALSE);
		}
		case 1:
		{
			CRUDeltaDef *pDdef = deltaDefList.GetAt(0);
			// A special case: update the refresh duration,
			// and (optionally) the delta size.
			UpdateSingleDeltaStatistics(pDdef, currDuration);
			break;
		}
		case 2:
		{
			prevDuration = rootMV.GetRefreshDurationEstimateWith_2_Deltas();
			nextDuration = EvaluateHeuristic(currDuration, prevDuration);
			rootMV.SetRefreshDurationEstimateWith_2_Deltas(nextDuration);
			break;
		}
		case 3:
		{
			prevDuration = rootMV.GetRefreshDurationEstimateWith_3_Deltas();
			nextDuration = EvaluateHeuristic(currDuration, prevDuration);
			rootMV.SetRefreshDurationEstimateWith_3_Deltas(nextDuration);
			break;
		}
		default:
		{
			prevDuration = rootMV.GetRefreshDurationEstimateWith_N_Deltas();
			nextDuration = EvaluateHeuristic(currDuration, prevDuration);
			rootMV.SetRefreshDurationEstimateWith_N_Deltas(nextDuration);
			break;
		}
	}
}
void CRURefreshTaskExecutor::
UpdateSingleDeltaStatistics(CRUDeltaDef *pDdef, TInt32 currDuration)
{
	CRUMV &rootMV = GetRootMV();

	TInt32 prevDuration, nextDuration;
	prevDuration = rootMV.GetRefreshDurationEstimate(pDdef->tblUid_);
	
	nextDuration = EvaluateHeuristic(currDuration, prevDuration);
	rootMV.SetRefreshDurationEstimate(pDdef->tblUid_, nextDuration);

	// Appling the delta size computation heuristic
	
	// If there are no statistics, 0 is the default for the delta size
	TInt32 nextDelta = 0;

	if (NULL != pDdef->pStat_)
	{
		// There are statistics, hence the delta size is known
		TInt32 currDelta = pDdef->pStat_->GetDeltaSize();
		TInt32 prevDelta = rootMV.GetDeltaSizeEstimate(pDdef->tblUid_);
		nextDelta = EvaluateHeuristic(currDelta, prevDelta);
	}
	
	rootMV.SetDeltaSizeEstimate(pDdef->tblUid_, nextDelta);
}
void CRUAuditRefreshTaskExecutor::EpilogueHandleOnStatementMV()
{
	CRUMV &mv = GetRootMV();

	CRUTblList &tblList = mv.GetTablesUsedByMe();
	DSListPosition pos = tblList.GetHeadPosition();

	Int32 i=0;

	while (NULL != pos)
	{
		CRUTbl *pTbl = tblList.GetNext(pos);
	
		CDMPreparedStatement *pStat = 
			pLockTablesTEDynamicContainer_->GetPreparedStatement(i);

		// Perform the LOCK TABLE statement on the used table
		// (the lock overlaps the original RP open, therefore
		// guaranteeing the lock continuity).
		ExecuteStatement(*pStat,IDS_RU_IREFRESH_FAILED);

		// Release the DDL lock AND the read-protected open on the used table.
		pTbl->ReleaseResources();
	}
}
TInt64 CRURefreshTaskExecutor::CalculateTimeStamp()
{
	CRUTblList &tblList = GetRootMV().GetTablesUsedByMe();
	DSListPosition pos = tblList.GetHeadPosition();

	CRUTbl *pTbl = tblList.GetNext(pos);
	TInt64 minTS = pTbl->GetTimestamp();

	while (NULL != pos)
	{
		pTbl = tblList.GetNext(pos);
		TInt64 nextTS = pTbl->GetTimestamp();

		minTS = (nextTS < minTS) ? nextTS : minTS;
	}

	if (0 == minTS)
	{
		// If the timestamp has not been executed until now,
		// this is time to compute it.
		// RUASSERT(CDDObject::eRECOMPUTE == GetRootMV().GetRefreshType());
		minTS = CRUGlobals::GetCurrentTimestamp();
	}

	return minTS;
}
void CRUAuditRefreshTaskExecutor::PurgeData()
{
#ifdef _DEBUG
	CDSString msg(
		"\nPurging the data from materialized view " 
		+ 
		GetRootMVName());
	
	if (TRUE == isPopindex_)
	{
		msg += " and its secondary indexes";
	}

	msg += "...\n";
	CRUGlobals::GetInstance()->
		LogDebugMessage(CRUGlobals::DUMP_PURGEDATA,"",msg);
#endif

	GetRootMV().PurgeDataWithIndexes();

	TESTPOINT2(CRUGlobals::TESTPOINT103, GetRootMVName());

        // now start the remote states and do a recompute
	SetState(EX_REMOTE_START);
}
void CRURefreshTaskExecutor::FinalMetadataUpdate()
{
	CRURefreshTask *pParentTask = GetRefreshTask();
	RUASSERT (NULL != pParentTask);


	TInt32 currDuration = 0;
        TInt64 ts = CalculateTimeStamp();

	if (TRUE == pParentTask->NeedToExecuteInternalRefresh())
	{
		currDuration = GetTimerDuration();
	}
	
	CRUMV *pPrevMV, *pCurrMV = NULL;
	CRUMVList &mvList = pParentTask->GetMVList();
	DSListPosition pos = mvList.GetHeadPosition();

	while (NULL != pos)
	{
		pPrevMV = pCurrMV;
		pCurrMV = mvList.GetNext(pos);

		// Update the MV's REFRESHED_AT timestamp
		pCurrMV->SetTimestamp(ts);

                // publish the refresh event to the PUBLISH table
           NABoolean isRecomputePublish = (IsRecompute() == TRUE);
           pCurrMV->PublishMVRefresh(isRecomputePublish);
   
	   if (CDDObject::eON_STATEMENT != pCurrMV->GetRefreshType())
           {
		if (NULL == pPrevMV)
		{
			// This is the Root MV (the first in the list)
			if (CDDObject::eON_REQUEST == pCurrMV->GetRefreshType())
			{
				// For every table T used by MV, 
				// set MV.EPOCH[T]<--T.CURRENT_EPOCH.
				UpdateRootMVCurrentEpochVector();
			}
			
			UpdateRootMVStatistics(currDuration);
		}
		else
		{
			UpdateNonRootMVStatistics(pCurrMV, pPrevMV, currDuration);
		}
	   }
		
		pCurrMV->SaveMetadata();
	}

        if (CDDObject::eON_STATEMENT != GetRootMV().GetRefreshType())
        {
	IncrementTopMvCurrentEpoch();
        }
}
//--------------------------------------------------------------------------//
//	CRURefreshSQLComposer::ComposeControlQueryShapeCut() 
//
//--------------------------------------------------------------------------//
// LCOV_EXCL_START :rfi
void CRURefreshSQLComposer::ComposeShowExplain()
{
	sql_ = "INSERT INTO ";
	sql_ +=	GetRootMV().GetCatName() + "." + GetRootMV().GetSchName() + ".MV_REFRESH_PLANS ";
	sql_ += "SELECT '";
	sql_ += GetRootMV().GetName() +"',";
	sql_ += "PLAN_ID,";
	sql_ += "SEQ_NUM,";
	sql_ += "SUBSTRING(OPERATOR,1,30),";
	sql_ += "LEFT_CHILD_SEQ_NUM,";
	sql_ += "RIGHT_CHILD_SEQ_NUM,";
	sql_ += "SUBSTRING(TNAME,1,60),";
	sql_ += "CARDINALITY,";
	sql_ += "OPERATOR_COST,";
	sql_ += "TOTAL_COST,";
	sql_ += "SUBSTRING(DETAIL_COST,1,1024),";
	sql_ += "SUBSTRING(DESCRIPTION,1,2024)";
	sql_ += " FROM TABLE(EXPLAIN(NULL,'DESCRIPTOR_FOR_SQLSTMT'));";
}
//--------------------------------------------------------------------------//
//	CRURefreshSQLComposer::ComposeControlQueryShape() 
//
//
//--------------------------------------------------------------------------//
// LCOV_EXCL_START :rfi
void CRURefreshSQLComposer::ComposeControlQueryShape()
{
	RUASSERT(NULL != GetRootMV().GetMVForceOption());

	sql_ = "CONTROL QUERY SHAPE  ";

	ComposeQueryShape();

	sql_ += ";";
}
void CRURefreshTaskExecutor::UpdateRootMVCurrentEpochVector()
{
	CRUMV &rootMV = GetRootMV();
	CRUTblList &tblList = rootMV.GetTablesUsedByMe();

	DSListPosition pos = tblList.GetHeadPosition();
	while (NULL != pos)
	{
		CRUTbl *pTbl = tblList.GetNext(pos);
		rootMV.SetEpoch(pTbl->GetUID(), pTbl->GetCurrentEpoch());
	}
}
void CRUAuditRefreshTaskExecutor::PrologueHandleOnStatementMV()
{
	CRUTblList &tblList = GetRootMV().GetTablesUsedByMe();
	DSListPosition pos = tblList.GetHeadPosition();
		
	while (NULL != pos)
	{
		CRUTbl *pTbl = tblList.GetNext(pos);

		pTbl->ExecuteReadProtectedOpen();
	}
}
void CRUAuditRefreshTaskExecutor::Init()
{
	inherited::Init();
	
	RUASSERT(TRUE == HasWork());

	if (FALSE == GetRefreshTask()->NeedToExecuteInternalRefresh())
	{
		return;
	}

        Lng32 refreshPattern = GetRootMV().GetRefreshPatternMap();
	isPurgedata_ = (0 != (refreshPattern & CRUMV::PURGEDATA));
	isPopindex_ = (0 != (refreshPattern & CRUMV::POPINDEX));

	CRUMV &mv = GetRootMV();
	if (mv.GetCommitNRows() != 0 && 
		TRUE == GetRootMV().IsMultiTxnContext())
	{
		RUASSERT(TRUE == GetRefreshTask()->IsRecompute());

		// We need to drop multi-txn context table
		// becuase we are recomputing a multi-txn mv
		isDeleteMultiTxnContext_ = TRUE;
	}

	// We must synchronize between the table and the mv, so we need to 
	// lock the table partitions
	// Here we copy the partitions file names in order to allow access to 
	// the files in the remote process when DDOL is not built
	tableLockProtocol_ = new CRUTableLockProtocol();
	tableLockProtocol_->Init(mv.GetTablesUsedByMe(), 
				 GetRefreshTask()->GetDeltaDefList());

	ComposeMySql();
}
void CRURefreshSQLComposer::StartInternalRefresh()
{
	if (NULL == CRUGlobals::GetInstance()->GetOptions().
							FindDebugOption(CRUGlobals::DISPLAY_REFRESH,"") ) 
	{
		sql_ = "INTERNAL REFRESH ";
	}
	else
	{
		// LCOV_EXCL_START :dpm
		sql_ = "DISPLAY INTERNAL REFRESH ";
		// LCOV_EXCL_STOP
	}
	
	sql_  += GetRootMV().GetFullName();
}
void CRUAuditRefreshTaskExecutor::ComposeMySql()
{
	CRUSimpleRefreshSQLComposer myComposer(GetRefreshTask());
	CRUMV &rootMV = GetRootMV();        	

	if (TRUE == isDeleteMultiTxnContext_)
	{
		myComposer.ComposeDeleteContextLogTable();

		auditRefreshTEDynamicContainer_.SetStatementText
			(DELETE_MULT_TXN_CTX_TBL,myComposer.GetSQL());
	}

        // POPINDEX CatApi request
	if (TRUE == isPopindex_)
	{
		numOfIndexes_ = rootMV.GetIndexList().GetCount();
		              
		if (0 < numOfIndexes_)
		{
			ComposeIndexesSql();
		}
	}

	// Compose the LOCK TABLE sql statements for locking all tables 
	// in the on statement MV initialization 
	if (CDDObject::eON_STATEMENT == GetRootMVType())
	{	
		CRUTblList &tblList = rootMV.GetTablesUsedByMe();
		
		DSListPosition pos = tblList.GetHeadPosition();
		
		pLockTablesTEDynamicContainer_ = 
			new CRUSQLDynamicStatementContainer((short)tblList.GetCount());
		
		Int32 i=0;
		
		while (NULL != pos)
		{
			CRUTbl *pTbl = tblList.GetNext(pos);
			myComposer.ComposeLock(pTbl->GetFullName(), FALSE /*shared*/);
			pLockTablesTEDynamicContainer_->SetStatementText
				(i,myComposer.GetSQL());
			i++;
		}
	}
}
//--------------------------------------------------------------------------//
//	CRURefreshSQLComposer::ComposeQueryShape() 
//
// The IR tree for internal refresh  is as follows :
//
//				JOIN
//			   /	\
//           JOIN   UPDATE MV(sub-tree)
//			/    \
//        GRBY   SCAN
//         |      MV
//     DELTA CALC
//     (sub-tree)
//
// We allow the user to force the join between the MV and the GROUP BY
// block and the GROUP BY node above the DELTA CALCULATION sub-tree 
//--------------------------------------------------------------------------//
// LCOV_EXCL_START :rfi
void CRURefreshSQLComposer::ComposeQueryShape()
{
	CDSString grbyStr,joinStr;
	
	const CRUMVForceOptions& forceOption =
		*GetRootMV().GetMVForceOption();

	switch(forceOption.GetGroupByoption())
	{
		case CRUForceOptions::GB_HASH:
			grbyStr = " HASH_GROUPBY(CUT) ";
			break;
		case CRUForceOptions::GB_SORT:
			grbyStr = " SORT_GROUPBY(CUT) ";
			break;
		case CRUForceOptions::GB_NO_FORCE:
			grbyStr = " GROUPBY(CUT) ";
			break;
		default:
			RUASSERT(FALSE);
	}

	switch(forceOption.GetJoinoption())
	{
		case CRUForceOptions::JOIN_MERGE:
			joinStr = " MERGE_JOIN( ";
			break;
		case CRUForceOptions::JOIN_HASH:
			joinStr = " HYBRID_HASH_JOIN( ";
			break;
		case CRUForceOptions::JOIN_NESTED:
			joinStr = " NESTED_JOIN( ";
			break;
		case CRUForceOptions::JOIN_NO_FORCE:
			joinStr = " JOIN(";
			break;
		default:
			RUASSERT(FALSE);
	}

	sql_ += " JOIN( " + joinStr + grbyStr + ",CUT),CUT)";
}
void CRUUnAuditRefreshTaskExecutor::Init()
{
	inherited::Init();

	RUASSERT(TRUE == HasWork());

	if (FALSE == GetRefreshTask()->NeedToExecuteInternalRefresh())
	{
		return;
	}

	Lng32 refreshPattern = GetRootMV().GetRefreshPatternMap();
	isPurgedata_ = (0 != (refreshPattern & CRUMV::PURGEDATA));
	isPopindex_ = (0 != (refreshPattern & CRUMV::POPINDEX));

	// Compose the INTERNAL REFRESH 
	// + (optionally) the PopIndex CatApi request statements
	// + (optionally) the LOCK TABLE statements for ON STATEMENT MV
	ComposeMySql();
}
void CRURefreshTaskExecutor::CheckSingleDeltaRestriction()
{
	CRUMV &rootMV = GetRootMV();
	CRUTblList &tblList = rootMV.GetFullySyncTablesUsedByMe();

	DSListPosition pos = tblList.GetHeadPosition();
	while (NULL != pos)
	{
		CRUTbl *pTbl = tblList.GetNext(pos);
		RUASSERT (TRUE == pTbl->IsFullySynchronized());

		if (TRUE == pTbl->IsEmptyDeltaNeeded()
			&&
			TRUE == rootMV.IsDeltaNonEmpty(*pTbl))
		{
			CRUException errDesc;
			errDesc.SetError(IDS_RU_INCONSISTENT_JOIN);
			errDesc.AddArgument(rootMVName_);
			throw errDesc;
		}
	}
}
//--------------------------------------------------------------------------//
//	CRURefreshTaskExecutor::GetDefaultMdamOptForTable()
//
// If the table has more then two key columns and the range log is not empty
// then mdam must be forced on the table unless the user forced otherwise
//--------------------------------------------------------------------------//
CRUForceOptions::MdamOptions CRURefreshTaskExecutor::GetDefaultMdamOptForTable(CRUTbl &tbl)
{
	Int32 numTableKeyCol = tbl.GetKeyColumnList().GetCount();

	if (numTableKeyCol < 2)
	{
		return CRUForceOptions::MDAM_NO_FORCE;
	}

	if (FALSE == GetRefreshTask()->IsSingleDeltaRefresh())
	{
		return CRUForceOptions::MDAM_NO_FORCE;
	}

	const CRUDeltaDef *pDdef = GetRootMV().GetDeltaDefByUid(tbl.GetUID());
	
	if (NULL != pDdef && TRUE == pDdef->isRangeLogNonEmpty_)
	{
		return CRUForceOptions::MDAM_ON;
	}

	return CRUForceOptions::MDAM_NO_FORCE;
}
//--------------------------------------------------------------------------//
//	CRUAuditRefreshTaskExecutor::ComposeIndexesSql()
//
//--------------------------------------------------------------------------//
void CRUAuditRefreshTaskExecutor::ComposeIndexesSql()
{
	
	const CDDIndexList &indexList = GetRootMV().GetIndexList();

	if( NULL == pAuditPopIndexdynamicContainer_ )
          pAuditPopIndexdynamicContainer_ = 
		new CRUSQLDynamicStatementContainer(numOfIndexes_);
 
        if( NULL == pAuditAvailableIndeXdynamicContainer_ )
	  pAuditAvailableIndeXdynamicContainer_ =
		new CRUSQLDynamicStatementContainer(numOfIndexes_);

        if( NULL == pAuditUnavailableIndeXdynamicContainer_ )
	  pAuditUnavailableIndeXdynamicContainer_ = 
		new CRUSQLDynamicStatementContainer(numOfIndexes_);

        if( NULL == pAuditToggleOnIndexdynamicContainer_ )
          pAuditToggleOnIndexdynamicContainer_ =
		new CRUSQLDynamicStatementContainer(numOfIndexes_);

        if( NULL == pAuditToggleOffIndexdynamicContainer_ )
          pAuditToggleOffIndexdynamicContainer_ =
		new CRUSQLDynamicStatementContainer(numOfIndexes_);

	DSListPosition pos = indexList.GetHeadPosition();
	
	for (Int32 i=0;NULL != pos;i++)
	{
		CDDIndex *pddIndex = indexList.GetNext(pos);
	
		CDSString popIdxRqst;
		GetRootMV().GetPopIndexCatApiRequestText(popIdxRqst, pddIndex);

		pAuditPopIndexdynamicContainer_->SetStatementText(i, popIdxRqst);

		CDSString availablepopIdxRqst;
		GetRootMV().GetUpdateIndexStatusCatApiRequestText(availablepopIdxRqst, 
								TRUE, /*available*/
								pddIndex);

		pAuditAvailableIndeXdynamicContainer_->SetStatementText(i, availablepopIdxRqst);

		CDSString unavailableIdxRqst; 
		GetRootMV().GetUpdateIndexStatusCatApiRequestText(unavailableIdxRqst, 
								FALSE, /*unavailable*/
								pddIndex);

		pAuditUnavailableIndeXdynamicContainer_->SetStatementText(i, unavailableIdxRqst);

                CDSString auditOffIdxRqst;
                GetRootMV().GetToggleAuditCatApiRequestText(auditOffIdxRqst, 
								FALSE, /* audit OFF */
								pddIndex);

                pAuditToggleOffIndexdynamicContainer_->SetStatementText(i,auditOffIdxRqst);

                CDSString auditOnIdxRqst;
                GetRootMV().GetToggleAuditCatApiRequestText(auditOnIdxRqst, 
								TRUE, /* audit ON */
								pddIndex);

                pAuditToggleOnIndexdynamicContainer_->SetStatementText(i,auditOnIdxRqst);

	}
}
CDSString CRURefreshSQLComposer::GetContextLogName() const
{
	return " (RANGE_LOG_TABLE " + GetRootMV().GetFullName() + " ) ";
}