void CRUDupElimSQLComposer::ComposeUpdateRecsSearchPredicate(CDSString &pred)
{
	pred = "\nWHERE \n(";
	const CRULogCtlColDesc &desc1 = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_EPOCH];

	pred += ComposeQuotedColName(desc1.name_);
	pred += " BETWEEN " + TInt32ToStr(beginEpoch_) 
			+ " AND " + TInt32ToStr(endEpoch_) + ")\nAND ";

	CDSString ckClause;
	ComposeCKEqualSearchClause(ckClause);
	pred += ckClause;

	CDSString type1 = TInt32ToStr(CRUDupElimConst::IS_PART_OF_UPDATE);
	CDSString type2 = TInt32ToStr(
		CRUDupElimConst::IS_PART_OF_UPDATE + CRUDupElimConst::IS_DELETE);

	const CRULogCtlColDesc &desc2 = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_OPTYPE];
	CDSString optypeColName = ComposeQuotedColName(desc2.name_);

	pred += "\nAND (" + optypeColName + " = " + type1;
	pred += " OR " + optypeColName + " = " + type2 + ")";
}
void CRUDupElimSQLComposer::ComposeQueryText(Int32 type)
{	
	BOOL isPhase0Query = 
		(CRUDupElimConst::PHASE_0_QUERY == type) ? TRUE : FALSE;

	if (NULL == CRUGlobals::GetInstance()->GetOptions().
		    FindDebugOption(CRUGlobals::DISPLAY_DE_SEL,"") ) 
	{
		  sql_ = "";
	}
	else
	{
		sql_ = "DISPLAY ";
	}

	CDSString qControlColNames, qCKColNames, qOrderByList;

	ComposeQControlColNames(qControlColNames);
	// Generate the list of selected CK columns
	ComposeQClusteringKeyColNames(qCKColNames, FALSE);

	CDSString qryBase = "SELECT " + qControlColNames + ", " + qCKColNames;
	qryBase += "\nFROM " + iudLogName_ + "\nWHERE ";
	
	CDSString epochCol = ComposeQuotedColName(
		iudLogCtlColDescVec[CRUDupElimConst::OFS_EPOCH].name_);

	if (endEpoch_ - beginEpoch_ + 1 < CRUDupElimConst::MAX_SELECT_CLAUSES)
	{
		// Reasonable number of epochs - optimizable query
		for (TInt32 i=beginEpoch_; i<=endEpoch_; i++)		
		{
			if (TRUE == isSingleRow_)
			{
				ComposeQBlockForEpoch(qryBase, epochCol, i, isPhase0Query);
			}

			if (TRUE == isRange_)
			{
				ComposeQBlockForEpoch(qryBase, epochCol, -i, isPhase0Query);
			}
		}
	}
	else
	{
		// Number of epochs too big
		ComposeQBlockForMultipleEpochs(qryBase, epochCol, isPhase0Query);
	}

	// Generate the list of CK columns for the ORDER BY clause
	// (with the ASC/DESC specifiers)
	ComposeQClusteringKeyColNames(qOrderByList, TRUE);

	sql_ += "\nORDER BY " + qOrderByList + ", ";
        sql_ += ComposeQuotedColName("TS");

	// I am the only one working on this portion of the log...
	sql_ += "\nFOR BROWSE ACCESS;";
}
void CRUDupElimSQLComposer::ComposeQControlColNames(CDSString &to)
{
	for (Int32 i=0; i<nCtrlColumns_; i++)
	{
		to += ComposeQuotedColName(iudLogCtlColDescVec[i].name_);
		to += ", ";
	}

	// Add the log's timestamp to the select list
	to += ComposeQuotedColName("TS");
}
void CRUDupElimSQLComposer::ComposeIUDUpdateBitmapText()
{
	CDSString pred;
	sql_ += "UPDATE " + iudLogName_;
	
	const CRULogCtlColDesc &desc = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_UPD_BMP];

	// Compose the real datatype 
	// of the @UPDATE_BITMAP column - CHAR(<size>)
	CDSString datatype(desc.datatype_);

	RUASSERT(updateBmpSize_ > 0);
	datatype += "(" + TInt32ToStr(updateBmpSize_) + ")";

	// -------------------------------------------------------------
    // Date: 2008-03-19  Caroline:
	// In UNICODE config: ISO_MAPPING=UTF8, DEFAULT_CHARSET= UCS2
	// The IUD_LOG_TABLE Clause: 
	//       SET "@UPDATE_BITMAP" = CAST (? AS CHAR(8)) 
	// The "@UPDATE_BITMAP" column is in ISO88591, and the CAST Clause 
	// is implied to UCS2, so we got the incompatible error. 
	// To fix the error, we explicitly say "CHARACTER SET ISO88591".

	datatype += " CHARACTER SET ISO88591 ";
	//---------------------------------------------

	sql_ += "\nSET " + ComposeQuotedColName(desc.name_) + " = ";
	sql_ += ComposeCastExpr(datatype);		

	ComposeUpdateRecsSearchPredicate(pred);
	sql_+= pred + ";";
}
void CRUDupElimSQLComposer::ComposeRngDeleteText()
{
	sql_ += "DELETE FROM " + rngLogName_ + "\nWHERE ";

	// @EPOCH = ? AND @RANGE_ID = ? AND
	for (Int32 i=0; i<2; i++)
	{
		sql_ += ComposeQuotedColName(rngLogCtlColDescVec[i].name_) + "=";
		sql_ += ComposeCastExpr(rngLogCtlColDescVec[i].datatype_);
		sql_ += "\nAND ";
	}

	CDSString rightOp;	// (?, ?, ..) DIRECTEDBY (...)
	ComposeTupleComparisonRightOperand(rightOp);

	CDSString rngBoundaryColNames;
	ComposeRngBoundaryColNames("BR_", rngBoundaryColNames);
	rngBoundaryColNames = "(" + rngBoundaryColNames + ")";

	// (@BR_col1, @BR_col2, ...) >= (?, ?, ..) DIRECTEDBY (...)
	sql_ += rngBoundaryColNames + " >= " + rightOp;

	sql_+= "\nAND ";
	// (@ER_col1, @ER_col2, ...) <= (?, ?, ..) DIRECTEDBY (...)
	ComposeRngBoundaryColNames("ER_", rngBoundaryColNames);
	rngBoundaryColNames = "(" + rngBoundaryColNames + ")";
	sql_ += rngBoundaryColNames + " <= " + rightOp;

	// (@ER_col1, @ER_col2, ...) <= (?, ?, ..) DIRECTEDBY (...)
	// This clause is added for performance
	sql_+= "\nAND ";
	sql_ += rngBoundaryColNames + " >= " + rightOp;
}
void CRUDupElimSQLComposer::ComposeSingleIUDRecSearchPredicate(CDSString &pred)
{
	pred = "\nWHERE ";
	// @EPOCH=?
	const CRULogCtlColDesc &desc = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_EPOCH];

	pred += ComposeQuotedColName(desc.name_);
	pred += "=" + ComposeCastExpr(desc.datatype_) + "\nAND ";

	CDSString ckClause;
	ComposeCKEqualSearchClause(ckClause);
	pred += ckClause;

        pred += "\nAND ";
        pred += ComposeQuotedColName("TS");
	pred += " = " + ComposeCastExpr("LARGEINT");
}
void CRULogCleanupSQLComposer::ComposeRangeLogCleanup()
{
	ComposeHeader(tbl_.GetRangeLogFullName(), CRULogCleanupTaskExecutor::CLEAN_IUD_FIRSTN);

	CDSString epochCol("EPOCH");
	epochCol = ComposeQuotedColName(CRUTbl::logCrtlColPrefix, epochCol);

	sql_ += "\nWHERE\n(" + epochCol + " <= ";
	// The largest obsolete epoch
	sql_ += CRUSQLComposer::TInt32ToStr(maxInapplicableEpoch_) + ");";
}
void CRUDupElimSQLComposer::ComposeUpdateIgnorePrefix(CDSString &cmdPrefix)
{
	cmdPrefix = "UPDATE " + iudLogName_;
	
	// SET @IGNORE=?
	cmdPrefix += "\nSET ";
	const CRULogCtlColDesc &desc = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_IGNORE];

	cmdPrefix += ComposeQuotedColName(desc.name_);
	cmdPrefix += "=" + ComposeCastExpr(desc.datatype_);
}
CDSString CRUDupElimSQLComposer::
ComposeIUDLogKeyColName(const CRUKeyColumn *pKeyCol)
{
	CDSString name(pKeyCol->GetName());

	if (CDSString("SYSKEY") == name)
	{
		// If the original table has a syskey, it becomes @SYSKEY in the log
		// (the log has a syskey of its own).
		name = ComposeQuotedColName(name);
	}

	return name;
}
void CRUDupElimSQLComposer::ComposeRngInsertColNames()
{
	sql_ += "\n(";
	for (Int32 i=0; i<CRUDupElimConst::NUM_RNG_LOG_CONTROL_COLS; i++)
	{
		sql_ += ComposeQuotedColName(rngLogCtlColDescVec[i].name_);
		sql_ += ", ";
	}

	CDSString rngBoundaryColNames;
	ComposeRngBoundaryColNames("BR_", rngBoundaryColNames);
	sql_ += rngBoundaryColNames + ", ";
	ComposeRngBoundaryColNames("ER_", rngBoundaryColNames);
	sql_ += rngBoundaryColNames + ")";
}
void CRUDupElimSQLComposer::ComposeIUDUpdateOptypeText()
{
	CDSString pred;
	sql_ += "UPDATE " + iudLogName_;
	
	const CRULogCtlColDesc &desc = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_OPTYPE];
	CDSString name = ComposeQuotedColName(desc.name_);

	sql_ += "\nSET " + name + " = ";
	sql_ += name + "-" + TInt32ToStr(CRUDupElimConst::IS_PART_OF_UPDATE);

	ComposeUpdateRecsSearchPredicate(pred);
	sql_+= pred + ";";
}
void CRUDupElimSQLComposer::ComposeIUDSubsetDeleteText()
{
	CDSString pred("");

	sql_ += "DELETE FROM " + iudLogName_;
	
	// Common predicate part
	CDSString epochOp("=");
	ComposeSubsetIUDRecSearchPredicate(pred, epochOp);

        pred += "\nAND ";
        pred += ComposeQuotedColName("TS");
	pred += " > " + ComposeCastExpr("LARGEINT");
	
	sql_ += "\n" + pred + ";";
}
void CRUDupElimSQLComposer::ComposeIUDSubsetUpdateAlwaysIgnoreText()
{
	CDSString cmdPrefix;
	CDSString pred;

	// UPDATE ... SET
	ComposeUpdateIgnorePrefix(cmdPrefix);
	sql_ += cmdPrefix;

	// Common predicate part
	CDSString epochOp("=");
	ComposeSubsetIUDRecSearchPredicate(pred, epochOp);

	pred += "\nAND ";
        pred += ComposeQuotedColName("TS");
	pred += " > " + ComposeCastExpr("LARGEINT");

	sql_ += "\n" + pred + ";";
}
void CRULogCleanupSQLComposer::ComposeIUDLogCleanup(CRULogCleanupTaskExecutor::SQL_STATEMENT type)
{
	ComposeHeader(tbl_.GetIUDLogFullName(), type);

	CDSString epochCol("EPOCH");
	epochCol = ComposeQuotedColName(CRUTbl::logCrtlColPrefix, epochCol);

	// For single-row records
	sql_ += "\nWHERE\n(" + epochCol + " BETWEEN ";

	// MAX_SPECIAL_EPOCH+1 is the smallest non-special epoch
	sql_ += CRUSQLComposer::TInt32ToStr(MAX_SPECIAL_EPOCH+1) + " AND ";
	// The largest obsolete epoch
	sql_ += CRUSQLComposer::TInt32ToStr(maxInapplicableEpoch_) + ")\n";

	// For range records
	sql_ += "OR\n(" + epochCol + " BETWEEN ";
	sql_ += CRUSQLComposer::TInt32ToStr(-maxInapplicableEpoch_);
	sql_ += " AND 0);";
}
void CRUDupElimSQLComposer::ComposeIUDSubsetUpdateIgnoreText()
{
	CDSString cmdPrefix;
	CDSString pred;

	// UPDATE ... SET
	ComposeUpdateIgnorePrefix(cmdPrefix);
	sql_ += cmdPrefix;

	// Common predicate part
	CDSString epochOp("=");
	ComposeSubsetIUDRecSearchPredicate(pred, epochOp);

	// AND @IGNORE < ?
	const CRULogCtlColDesc &desc = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_IGNORE];
	pred += "\nAND " + ComposeQuotedColName(desc.name_);
	pred += "<" + ComposeCastExpr(desc.datatype_);

	sql_ += "\n" + pred + ";";
}
void CRUDupElimSQLComposer::
ComposeSubsetIUDRecSearchPredicate(CDSString &pred, CDSString &epochOp)
{
	pred = "WHERE ";

	// @EPOCH <epochOp> ?
	const CRULogCtlColDesc &desc1 = 
		iudLogCtlColDescVec[CRUDupElimConst::OFS_EPOCH];
	pred += ComposeQuotedColName(desc1.name_);
	pred += epochOp + ComposeCastExpr(desc1.datatype_);

	CDSString rightOp;	// (?, ?, ..) DIRECTEDBY (...)
	ComposeTupleComparisonRightOperand(rightOp);

	CDSString rngBoundaryColNames;
	ComposeRngBoundaryColNames("" /*no prefix*/, rngBoundaryColNames);
	rngBoundaryColNames = "(" + rngBoundaryColNames + ")";

	// (col1, col2, ...) >= (?, ?, ..) DIRECTEDBY (...)
	pred += "\nAND " + rngBoundaryColNames + " >= " + rightOp;

	// (col1, col2, ...) <= (?, ?, ..) DIRECTEDBY (...)
	pred += "\nAND " + rngBoundaryColNames + " <= " + rightOp;
}