Files
mars-flaim/flaim/src/fqlog.cpp

885 lines
21 KiB
C++

//-------------------------------------------------------------------------
// Desc: Query logging
// Tabs: 3
//
// Copyright (c) 2001,2003,2005-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: fqlog.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
//-------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC void flmLogIndent(
IF_LogMessageClient * pLogMsg,
FLMUINT uiIndent);
FSTATIC void flmLogOperator(
IF_LogMessageClient * pLogMsg,
QTYPES eOperator,
FLMBOOL bEndLine);
FSTATIC void flmLogBinary(
IF_LogMessageClient * pLogMsg,
FLMBYTE * pucBuf,
FLMUINT uiBufLen);
FSTATIC void flmLogText(
IF_LogMessageClient * pLogMsg,
const char * pucBuf,
FLMUINT uiBufLen);
FSTATIC void flmLogPredicate(
IF_LogMessageClient * pLogMsg,
FLMUINT uiIndent,
FQNODE * pQNode);
FSTATIC void flmLogSubQuery(
IF_LogMessageClient * pLogMsg,
FLMUINT uiIndent,
QTYPES eParentOp,
SUBQUERY * pSubQuery);
/****************************************************************************
Desc: This routine indents in the log.
****************************************************************************/
FSTATIC void flmLogIndent(
IF_LogMessageClient * pLogMsg,
FLMUINT uiIndent)
{
char szIndent [100];
if (uiIndent)
{
f_memset( szIndent, ' ', uiIndent);
szIndent [uiIndent] = 0;
pLogMsg->changeColor( FLM_LIGHTGRAY, FLM_BLACK);
pLogMsg->appendString( szIndent);
}
}
/****************************************************************************
Desc: This routine logs an operator
****************************************************************************/
FSTATIC void flmLogOperator(
IF_LogMessageClient * pLogMsg,
QTYPES eOperator,
FLMBOOL bEndLine)
{
const char * pszOperator;
switch (eOperator)
{
case FLM_AND_OP:
pszOperator = "AND";
break;
case FLM_OR_OP:
pszOperator = "OR";
break;
case FLM_NOT_OP:
pszOperator = "!";
break;
case FLM_EQ_OP:
pszOperator = "==";
break;
case FLM_MATCH_OP:
pszOperator = "MATCH";
break;
case FLM_MATCH_BEGIN_OP:
pszOperator = "MATCHBEGIN";
break;
case FLM_MATCH_END_OP:
pszOperator = "MATCHEND";
break;
case FLM_CONTAINS_OP:
pszOperator = "CONTAINS";
break;
case FLM_NE_OP:
pszOperator = "!=";
break;
case FLM_LT_OP:
pszOperator = "<";
break;
case FLM_LE_OP:
pszOperator = "<=";
break;
case FLM_GT_OP:
pszOperator = ">";
break;
case FLM_GE_OP:
pszOperator = ">=";
break;
case FLM_BITAND_OP:
pszOperator = "&";
break;
case FLM_BITOR_OP:
pszOperator = "|";
break;
case FLM_BITXOR_OP:
pszOperator = "^";
break;
case FLM_MULT_OP:
pszOperator = "*";
break;
case FLM_DIV_OP:
pszOperator = "/";
break;
case FLM_MOD_OP:
pszOperator = "%";
break;
case FLM_PLUS_OP:
pszOperator = "+";
break;
case FLM_MINUS_OP:
case FLM_NEG_OP:
pszOperator = "-";
break;
case FLM_LPAREN_OP:
pszOperator = "(";
break;
case FLM_RPAREN_OP:
pszOperator = ")";
break;
default:
pszOperator = "UNKNOWN";
break;
}
pLogMsg->pushForegroundColor();
pLogMsg->pushBackgroundColor();
if (eOperator == FLM_LPAREN_OP || eOperator == FLM_RPAREN_OP)
{
pLogMsg->changeColor( FLM_CYAN, FLM_BLACK);
}
else
{
pLogMsg->changeColor( FLM_BLUE, FLM_LIGHTGRAY);
}
pLogMsg->appendString( pszOperator);
pLogMsg->popForegroundColor();
pLogMsg->popBackgroundColor();
if( bEndLine)
{
pLogMsg->newline();
}
}
/****************************************************************************
Desc: Format a byte into two HEX characters.
****************************************************************************/
FINLINE void flmFormatByteToHex(
char * pszBuf,
FLMBYTE ucChar)
{
FLMUINT uiNibble = ((FLMUINT)ucChar >> 4) & 0xF;
*pszBuf++ = (FLMBYTE)(uiNibble <= 9
? (FLMBYTE)(uiNibble + '0')
: (FLMBYTE)(uiNibble - 10 + 'A'));
uiNibble = (FLMUINT)ucChar & 0xF;
*pszBuf = (FLMBYTE)(uiNibble <= 9
? (FLMBYTE)(uiNibble + '0')
: (FLMBYTE)(uiNibble - 10 + 'A'));
}
/****************************************************************************
Desc: This routine logs a buffer of binary bytes as ASCII hex.
****************************************************************************/
FSTATIC void flmLogBinary(
IF_LogMessageClient * pLogMsg,
FLMBYTE * pucBuf,
FLMUINT uiBufLen)
{
FLMUINT uiLoop;
FLMUINT uiOffset;
char szBuf [128];
FLMBYTE ucChar;
FLMUINT uiRepeatCnt;
FLMUINT uiCharsNeeded;
FLMBOOL bFirstChar = TRUE;
uiLoop = 0;
uiOffset = 0;
while (uiLoop < uiBufLen)
{
// See how many there are of this byte.
ucChar = *pucBuf;
uiRepeatCnt = 1;
uiLoop++;
pucBuf++;
while (uiLoop < uiBufLen && *pucBuf == ucChar)
{
uiLoop++;
pucBuf++;
uiRepeatCnt++;
}
// If this is the first character, we need 2 characters
// for the HEX digits. If not the first character,
// we need 3 character - one leading space and 2 for hex digits.
uiCharsNeeded = (FLMUINT)(bFirstChar
? (FLMUINT)2
: (FLMUINT)3);
// Calculate number of characters needed for
// the ":cnt" after the hex digits if we have
// the character repeated more than once.
if (uiRepeatCnt > 1)
{
FLMUINT uiTmp = uiRepeatCnt;
while (uiTmp)
{
uiCharsNeeded++;
uiTmp /= 10;
}
uiCharsNeeded++; // Add one for the colon.
}
// Don't overflow the buffer.
if (uiOffset >= sizeof( szBuf) - uiCharsNeeded)
{
szBuf [uiOffset] = 0;
pLogMsg->appendString( szBuf);
uiOffset = 0;
}
// Put a space between bytes.
if (!bFirstChar)
{
szBuf [uiOffset++] = ' ';
}
else
{
bFirstChar = FALSE;
}
flmFormatByteToHex( &szBuf [uiOffset], ucChar);
uiOffset += 2;
if (uiRepeatCnt > 1)
{
szBuf [uiOffset++] = ':';
f_sprintf( (char *)&szBuf [uiOffset], "%u", (unsigned)uiRepeatCnt);
while (szBuf [uiOffset])
{
uiOffset++;
}
}
}
// Output whatever has not been output so far.
if (uiOffset)
{
szBuf [uiOffset] = 0;
pLogMsg->appendString( szBuf);
}
}
/****************************************************************************
Desc: This routine logs text data.
****************************************************************************/
FSTATIC void flmLogText(
IF_LogMessageClient * pLogMsg,
const char * pucBuf,
FLMUINT uiBufLen)
{
FLMUINT uiLoop;
FLMUINT uiOffset;
FLMBYTE ucChar;
FLMUINT uiObjType;
FLMUINT uiObjLength = 0;
char szBuf[ 128];
uiOffset = 0;
for (uiLoop = 0, uiOffset = 0;
uiLoop < uiBufLen;
pucBuf += uiObjLength, uiLoop += uiObjLength)
{
// Don't overflow the buffer - must have room for maximum bytes needed
// to represent a character.
if (uiOffset >= sizeof( szBuf) - 14)
{
szBuf [uiOffset] = 0;
pLogMsg->appendString( szBuf);
uiOffset = 0;
}
ucChar = *pucBuf;
uiObjType = flmTextObjType( ucChar);
switch (uiObjType)
{
case ASCII_CHAR_CODE: // 0nnnnnnn
uiObjLength = 1;
// Character set zero is assumed.
szBuf [uiOffset++] = ucChar;
break;
case CHAR_SET_CODE: // 10nnnnnn
uiObjLength = 2;
// Character set followed by character
f_strcpy( &szBuf [uiOffset], "~[UC-0x");
uiOffset += 7;
flmFormatByteToHex( &szBuf [uiOffset], ucChar & (~CHAR_SET_MASK));
flmFormatByteToHex( &szBuf [uiOffset + 2], *(pucBuf + 1));
szBuf [uiOffset + 4] = ']';
uiOffset += 5;
break;
case WHITE_SPACE_CODE: // 110nnnnn
uiObjLength = 1;
szBuf [uiOffset++] = ' ';
break;
case EXT_CHAR_CODE:
uiObjLength = 3;
// Character set followed by character
f_strcpy( &szBuf [uiOffset], "~[WP-0x");
uiOffset += 7;
flmFormatByteToHex( &szBuf [uiOffset], *(pucBuf + 1));
flmFormatByteToHex( &szBuf [uiOffset + 2], *(pucBuf + 2));
szBuf [uiOffset + 4] = ']';
uiOffset += 5;
break;
case OEM_CODE:
// OEM characters are always >= 128
// Use character set zero to process them.
uiObjLength = 2;
szBuf [uiOffset++] = *(pucBuf + 1);
break;
case UNICODE_CODE: // Unconvertable UNICODE code
uiObjLength = 3;
// Unicode character followed by unicode character set
f_strcpy( &szBuf [uiOffset], "~[UC-0x");
uiOffset += 7;
flmFormatByteToHex( &szBuf [uiOffset], *(pucBuf + 1));
flmFormatByteToHex( &szBuf [uiOffset + 2], *(pucBuf + 2));
szBuf [uiOffset + 4] = ']';
uiOffset += 5;
break;
default:
// Should not happen
flmAssert( 0);
break;
}
}
// Log whatever has not yet been logged.
if (uiOffset)
{
szBuf [uiOffset] = 0;
pLogMsg->appendString( szBuf);
uiOffset = 0;
}
}
/****************************************************************************
Desc: This routine logs the query criteria for a cursor.
****************************************************************************/
FSTATIC void flmLogPredicate(
IF_LogMessageClient * pLogMsg,
FLMUINT uiIndent,
FQNODE * pQNode)
{
FLMUINT uiNestLevel = 0;
QTYPES eCurrentOp;
flmLogIndent( pLogMsg, uiIndent);
// Traverse the tree.
for (;;)
{
eCurrentOp = GET_QNODE_TYPE( pQNode);
if (IS_OP( eCurrentOp))
{
if (uiNestLevel)
{
flmLogOperator( pLogMsg, FLM_LPAREN_OP, FALSE);
}
pQNode = pQNode->pChild;
eCurrentOp = GET_QNODE_TYPE( pQNode);
uiNestLevel++;
continue;
}
if (IS_VAL( eCurrentOp))
{
pLogMsg->changeColor( FLM_WHITE, FLM_BLACK);
switch (eCurrentOp)
{
case FLM_BOOL_VAL:
f_logPrintf( pLogMsg, "%u",
(unsigned)pQNode->pQAtom->val.uiBool);
break;
case FLM_REC_PTR_VAL:
case FLM_UINT32_VAL:
f_logPrintf( pLogMsg, "%u",
(unsigned)pQNode->pQAtom->val.ui32Val);
break;
case FLM_UINT64_VAL:
f_logPrintf( pLogMsg, "%I64u",
pQNode->pQAtom->val.ui64Val);
break;
case FLM_INT32_VAL:
f_logPrintf( pLogMsg, "%d",
(int)pQNode->pQAtom->val.i32Val);
break;
case FLM_INT64_VAL:
f_logPrintf( pLogMsg, "%I64d",
pQNode->pQAtom->val.i64Val);
break;
case FLM_BINARY_VAL:
pLogMsg->appendString( "BINARY(");
flmLogBinary( pLogMsg, pQNode->pQAtom->val.pucBuf,
pQNode->pQAtom->uiBufLen);
pLogMsg->appendString( ")");
break;
case FLM_TEXT_VAL:
pLogMsg->appendString( "\"");
flmLogText( pLogMsg, (const char *)pQNode->pQAtom->val.pucBuf,
pQNode->pQAtom->uiBufLen);
pLogMsg->appendString( "\"");
break;
default:
flmAssert( 0);
break;
}
}
else
{
FLMUINT * puiFldPath = pQNode->pQAtom->val.QueryFld.puiFldPath;
FLMUINT uiCnt;
flmAssert( IS_FIELD( eCurrentOp));
pLogMsg->changeColor( FLM_YELLOW, FLM_BLACK);
pLogMsg->appendString( "FLD:");
// Fields are from child to parent order - must count fields
// and print out in parent to child order.
uiCnt = 0;
while (puiFldPath [uiCnt])
{
uiCnt++;
}
while (uiCnt)
{
uiCnt--;
if (uiCnt)
{
f_logPrintf( pLogMsg, "%u.", (unsigned)puiFldPath [uiCnt]);
}
else
{
f_logPrintf( pLogMsg, "%u", (unsigned)puiFldPath [uiCnt]);
}
}
}
if (!uiNestLevel)
{
goto Exit;
}
// Go to the sibling, if any.
while (!pQNode->pNextSib)
{
pQNode = pQNode->pParent;
uiNestLevel--;
if (!uiNestLevel)
{
goto Exit; // Done with this predicate.
}
flmLogOperator( pLogMsg, FLM_RPAREN_OP, FALSE);
}
// Have a sibling, log the operator.
eCurrentOp = GET_QNODE_TYPE( pQNode->pParent);
pLogMsg->appendString( " ");
flmLogOperator( pLogMsg, eCurrentOp, FALSE);
pLogMsg->appendString( " ");
pQNode = pQNode->pNextSib;
}
Exit:
pLogMsg->newline();
return;
}
/****************************************************************************
Desc: This routine logs the query criteria for a cursor.
****************************************************************************/
FSTATIC void flmLogSubQuery(
IF_LogMessageClient * pLogMsg,
FLMUINT uiIndent,
QTYPES eParentOp,
SUBQUERY * pSubQuery)
{
FQNODE * pQNode;
QTYPES eCurrentOp;
QTYPES eTmpParentOp;
FLMBYTE * pucFromKey;
FLMUINT uiFromKeyLen;
FLMBYTE * pucUntilKey;
FLMUINT uiUntilKeyLen;
FLMBOOL bUntilKeyExclusive;
FLMBOOL bIndentOptInfo = TRUE;
if ((pQNode = pSubQuery->pTree) == NULL)
{
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, FLM_LPAREN_OP, FALSE);
pLogMsg->changeColor( FLM_WHITE, FLM_BLACK);
pLogMsg->appendString( "<empty>");
flmLogOperator( pLogMsg, FLM_RPAREN_OP, TRUE);
goto Output_Opt_Info;
}
// Traverse the tree.
for (;;)
{
eCurrentOp = GET_QNODE_TYPE( pQNode);
eTmpParentOp = (QTYPES)(pQNode->pParent
? GET_QNODE_TYPE( pQNode->pParent)
: eParentOp);
if (eCurrentOp == FLM_AND_OP)
{
if (eTmpParentOp == FLM_OR_OP)
{
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, FLM_LPAREN_OP, TRUE);
uiIndent += 2;
bIndentOptInfo = FALSE;
}
pQNode = pQNode->pChild;
}
else if (eCurrentOp == FLM_OR_OP)
{
if (eTmpParentOp == FLM_AND_OP)
{
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, FLM_LPAREN_OP, TRUE);
uiIndent += 2;
}
pQNode = pQNode->pChild;
}
else if (eCurrentOp == FLM_USER_PREDICATE)
{
HFCURSOR hCursor = pQNode->pQAtom->val.pPredicate->getCursor();
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, FLM_LPAREN_OP, FALSE);
if (hCursor == HFCURSOR_NULL)
{
pLogMsg->changeColor( FLM_WHITE, FLM_BLACK);
pLogMsg->appendString( " [EmbeddedPredicate] ");
flmLogOperator( pLogMsg, FLM_RPAREN_OP, TRUE);
}
else
{
pLogMsg->changeColor( FLM_LIGHTGRAY, FLM_BLACK);
pLogMsg->appendString( " [BeginEmbedded");
if (pSubQuery->OptInfo.eOptType == QOPT_USING_PREDICATE &&
pSubQuery->pPredicate == pQNode->pQAtom->val.pPredicate)
{
pLogMsg->appendString( ", Optimized]");
}
else
{
pLogMsg->appendString( "]");
}
bIndentOptInfo = FALSE;
pLogMsg->newline();
uiIndent += 2;
flmLogQuery( pLogMsg, uiIndent, (CURSOR *)hCursor);
uiIndent -= 2;
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, FLM_RPAREN_OP, FALSE);
pLogMsg->changeColor( FLM_LIGHTGRAY, FLM_BLACK);
pLogMsg->appendString( " [EndEmbedded]");
pLogMsg->newline();
}
goto Traverse_Up;
}
else
{
flmAssert( eCurrentOp != FLM_NOT_OP);
if (!pQNode->pNextSib && !pQNode->pParent)
{
flmLogPredicate( pLogMsg, uiIndent, pQNode);
}
else
{
flmLogPredicate( pLogMsg, uiIndent + 2, pQNode);
bIndentOptInfo = FALSE;
}
Traverse_Up:
while (!pQNode->pNextSib)
{
if ((pQNode = pQNode->pParent) == NULL)
{
goto Output_Opt_Info;
}
eCurrentOp = GET_QNODE_TYPE( pQNode);
eTmpParentOp = (QTYPES)(pQNode->pParent
? GET_QNODE_TYPE( pQNode->pParent)
: eParentOp);
if ((eCurrentOp == FLM_AND_OP && eTmpParentOp == FLM_OR_OP) ||
(eCurrentOp == FLM_OR_OP && eTmpParentOp == FLM_AND_OP))
{
flmAssert( uiIndent >= 2);
uiIndent -= 2;
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, FLM_RPAREN_OP, TRUE);
}
}
// Have a sibling.
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, eTmpParentOp, TRUE);
pQNode = pQNode->pNextSib;
}
}
Output_Opt_Info:
if (bIndentOptInfo)
{
uiIndent += 2;
}
flmLogIndent( pLogMsg, uiIndent);
pLogMsg->appendString( "{OptInfo: ");
switch (pSubQuery->OptInfo.eOptType)
{
case QOPT_USING_INDEX:
f_logPrintf( pLogMsg, F_FOREWHITE "UsingIX=" F_FOREYELLOW "%u",
pSubQuery->OptInfo.uiIxNum);
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", KeyMatch=");
if (pSubQuery->OptInfo.bDoKeyMatch)
{
f_logPrintf( pLogMsg, F_FOREGREEN "YES");
}
else
{
f_logPrintf( pLogMsg, F_FORERED "NO");
}
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", RecMatch=");
if (pSubQuery->OptInfo.bDoRecMatch)
{
f_logPrintf( pLogMsg, F_FOREGREEN "YES");
}
else
{
f_logPrintf( pLogMsg, F_FORERED "NO");
}
pucFromKey = NULL;
pucUntilKey = NULL;
if (RC_OK( pSubQuery->pFSIndexCursor->getFirstLastKeys(
&pucFromKey, &uiFromKeyLen,
&pucUntilKey, &uiUntilKeyLen,
&bUntilKeyExclusive)))
{
// Show the from key
f_logPrintf( pLogMsg,
F_FORELIGHTGRAY ", FromKeyLen=" F_FOREYELLOW "%u"
F_FORELIGHTGRAY ", FromKey=(",
uiFromKeyLen);
if (uiFromKeyLen)
{
pLogMsg->changeColor( FLM_YELLOW, FLM_BLACK);
flmLogBinary( pLogMsg, pucFromKey, uiFromKeyLen);
}
else
{
f_logPrintf( pLogMsg, F_FOREYELLOW "<empty>");
}
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ")");
// Show the until key.
f_logPrintf( pLogMsg,
F_FORELIGHTGRAY ", UntilKeyLen=" F_FOREYELLOW "%u"
F_FORELIGHTGRAY ", UntilExcl=" F_FOREYELLOW "%s"
F_FORELIGHTGRAY ", UntilKey=(",
uiUntilKeyLen,
(bUntilKeyExclusive
? "Yes"
: "No"));
if (uiUntilKeyLen)
{
pLogMsg->changeColor( FLM_YELLOW, FLM_BLACK);
flmLogBinary( pLogMsg, pucUntilKey, uiUntilKeyLen);
}
else
{
f_logPrintf( pLogMsg, F_FOREYELLOW "<empty>");
}
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ")");
f_free( &pucFromKey);
f_free( &pucUntilKey);
}
break;
case QOPT_USING_PREDICATE:
f_logPrintf( pLogMsg, F_FOREWHITE "Using Embedded Predicate");
break;
case QOPT_SINGLE_RECORD_READ:
f_logPrintf( pLogMsg, F_FOREWHITE "Single Record Read, DRN: "
F_FOREYELLOW "%u", pSubQuery->OptInfo.uiDrn);
break;
case QOPT_PARTIAL_CONTAINER_SCAN:
f_logPrintf( pLogMsg, F_FOREWHITE "Partial Container Scan");
//VISIT: Output from and until DRNs - need a method from
//pSubQuery->pFSDataCursor to return them.
break;
case QOPT_FULL_CONTAINER_SCAN:
f_logPrintf( pLogMsg, F_FOREWHITE "Full Container Scan");
break;
default:
f_logPrintf( pLogMsg, F_FOREWHITE "Unknown optimization");
break;
}
f_logPrintf( pLogMsg, F_FORELIGHTGRAY "}\n");
flmLogIndent( pLogMsg, uiIndent);
pLogMsg->appendString( "{Stats: ");
f_logPrintf( pLogMsg, F_FORELIGHTGRAY "Container=" F_FOREWHITE "%u",
(unsigned)pSubQuery->SQStatus.uiContainerNum);
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", Matched=" F_FOREWHITE "%u",
(unsigned)pSubQuery->SQStatus.uiMatchedCnt);
if (pSubQuery->SQStatus.uiNumRejectedByCallback)
{
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", CallbackRejected=" F_FOREWHITE "%u",
(unsigned)pSubQuery->SQStatus.uiNumRejectedByCallback);
}
if (pSubQuery->SQStatus.uiDupsEliminated)
{
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", DupsElim=" F_FOREWHITE "%u",
(unsigned)pSubQuery->SQStatus.uiDupsEliminated);
}
if (pSubQuery->SQStatus.uiKeysTraversed ||
pSubQuery->SQStatus.uiKeysRejected)
{
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", KeysFailed=" F_FOREWHITE "%u of %u",
(unsigned)pSubQuery->SQStatus.uiKeysRejected,
(unsigned)pSubQuery->SQStatus.uiKeysTraversed);
}
if (pSubQuery->SQStatus.uiRefsTraversed ||
pSubQuery->SQStatus.uiRefsRejected)
{
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", RefsFailed=" F_FOREWHITE "%u of %u",
(unsigned)pSubQuery->SQStatus.uiRefsRejected,
(unsigned)pSubQuery->SQStatus.uiRefsTraversed);
}
if (pSubQuery->SQStatus.uiRecsFetchedForEval ||
pSubQuery->SQStatus.uiRecsRejected ||
pSubQuery->SQStatus.uiRecsNotFound)
{
f_logPrintf( pLogMsg, F_FORELIGHTGRAY ", RecsFetched=" F_FOREWHITE "%u"
F_FORELIGHTGRAY ", RecsRejected=" F_FOREWHITE "%u"
F_FORELIGHTGRAY ", RecsNotFound=" F_FOREWHITE "%u",
(unsigned)pSubQuery->SQStatus.uiRecsFetchedForEval,
(unsigned)pSubQuery->SQStatus.uiRecsRejected,
(unsigned)pSubQuery->SQStatus.uiRecsNotFound);
}
f_logPrintf( pLogMsg, F_FORELIGHTGRAY "}\n");
if (bIndentOptInfo)
{
flmAssert( uiIndent >= 2);
uiIndent -= 2;
}
}
/****************************************************************************
Desc: This routine logs the query criteria for a cursor.
****************************************************************************/
void flmLogQuery(
IF_LogMessageClient * pLogMsg,
FLMUINT uiIndent,
CURSOR * pCursor)
{
SUBQUERY * pSubQuery;
QTYPES eParentOp = (pCursor->pSubQueryList &&
pCursor->pSubQueryList->pNext)
? FLM_OR_OP
: NO_TYPE;
if (!uiIndent)
{
pLogMsg->changeColor( FLM_LIGHTGRAY, FLM_BLACK);
pLogMsg->appendString( "QUERY CRITERIA:");
if (!pCursor->pSubQueryList)
{
pLogMsg->appendString( " <NO CRITERIA>");
}
pLogMsg->newline();
uiIndent += 2;
}
// Output each sub-query.
pSubQuery = pCursor->pSubQueryList;
while (pSubQuery)
{
flmLogSubQuery( pLogMsg, uiIndent, eParentOp, pSubQuery);
if ((pSubQuery = pSubQuery->pNext) != NULL)
{
flmLogIndent( pLogMsg, uiIndent);
flmLogOperator( pLogMsg, FLM_OR_OP, TRUE);
}
}
}