Files
mars-flaim/flaim/src/fqeval.cpp
ahodgkinson f54e6ce080 Changed license to LGPL.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2007-01-23 09:38:48 +00:00

3882 lines
82 KiB
C++

//-------------------------------------------------------------------------
// Desc: Query evaluation
// Tabs: 3
//
// Copyright (c) 1994-2007 Novell, Inc. All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version 2.1
// of the License.
//
// This library 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
// Library Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; 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$
//------------------------------------------------------------------------------
#include "flaimsys.h"
#define IS_UNSIGNED( e) ((e) == FLM_UINT32_VAL || (e) == FLM_UINT64_VAL)
#define IS_SIGNED( e) ((e) == FLM_INT32_VAL || (e) == FLM_INT64_VAL)
FSTATIC FLMUINT flmCurEvalTrueFalse(
FQATOM * pElm);
FSTATIC RCODE flmCurGetAtomFromRec(
FDB * pDb,
F_Pool * pPool,
FQATOM * pTreeAtom,
FlmRecord * pRecord,
QTYPES eFldType,
FLMBOOL bGetAtomVals,
FQATOM * pResult,
FLMBOOL bHaveKey);
FSTATIC RCODE flmFieldIterate(
FDB * pDb,
F_Pool * pPool,
QTYPES eFldType,
FQNODE * pOpCB,
FlmRecord * pRecord,
FLMBOOL bHaveKey,
FLMBOOL bGetAtomVals,
FLMUINT uiAction,
FQATOM * pResult);
FSTATIC RCODE flmCurEvalArithOp(
FDB * pDb,
SUBQUERY * pSubQuery,
FlmRecord * pRecord,
FQNODE * pQNode,
QTYPES eOp,
FLMBOOL bGetNewField,
FLMBOOL bHaveKey,
FQATOM * pResult);
FSTATIC RCODE flmCurEvalLogicalOp(
FDB * pDb,
SUBQUERY * pSubQuery,
FlmRecord * pRecord,
FQNODE * pQNode,
QTYPES eOp,
FLMBOOL bHaveKey,
FQATOM * pResult);
#define IS_EXPORT_PTR(e) \
((e) == FLM_TEXT_VAL || (e) == FLM_BINARY_VAL)
FSTATIC void fqOpUUBitAND(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUUBitOR(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUUBitXOR(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUUMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUSMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSSMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSUMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUUDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUSDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSSDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSUDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUUMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUSMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSSMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSUMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUUPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUSPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSSPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSUPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUUMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpUSMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSSMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC void fqOpSUMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FSTATIC RCODE flmCurDoNeg(
FQATOM * pResult);
typedef void FQ_OPERATION(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult);
FQ_OPERATION * FQ_ArithOpTable[
((LAST_ARITH_OP - FIRST_ARITH_OP) + 1) * 4 ] =
{
/* U = Unsigned S = Signed
U + U U + S
S + U S + S */
/* BITAND */ fqOpUUBitAND, fqOpUUBitAND,
fqOpUUBitAND, fqOpUUBitAND,
/* BITOR */ fqOpUUBitOR, fqOpUUBitOR,
fqOpUUBitOR, fqOpUUBitOR,
/* BITXOR */ fqOpUUBitXOR, fqOpUUBitXOR,
fqOpUUBitXOR, fqOpUUBitXOR,
/* MULT */ fqOpUUMult, fqOpUSMult,
fqOpSUMult, fqOpSSMult,
/* DIV */ fqOpUUDiv, fqOpUSDiv,
fqOpSUDiv, fqOpSSDiv,
/* MOD */ fqOpUUMod, fqOpUSMod,
fqOpSUMod, fqOpSSMod,
/* PLUS */ fqOpUUPlus, fqOpUSPlus,
fqOpSUPlus, fqOpSSPlus,
/* MINUS */ fqOpUUMinus, fqOpUSMinus,
fqOpSUMinus, fqOpSSMinus
};
/***************************************************************************
Desc: Determines if number is the native type.
***************************************************************************/
FINLINE FLMBOOL isNativeNum(
QTYPES eType)
{
return( eType == FLM_UINT32_VAL || eType == FLM_INT32_VAL
? TRUE
: FALSE);
}
/***************************************************************************
Desc: Returns a 64-bit unsigned integer
***************************************************************************/
FINLINE FLMUINT64 fqGetUInt64(
FQATOM * pValue)
{
if (pValue->eType == FLM_UINT32_VAL)
{
return( (FLMUINT64)pValue->val.ui32Val);
}
else if( pValue->eType == FLM_UINT64_VAL)
{
return( pValue->val.ui64Val);
}
else if( pValue->eType == FLM_INT64_VAL)
{
if( pValue->val.i64Val >= 0)
{
return( (FLMUINT64)pValue->val.i64Val);
}
}
else if( pValue->eType == FLM_INT32_VAL)
{
if( pValue->val.i32Val >= 0)
{
return( (FLMUINT64)pValue->val.i32Val);
}
}
flmAssert( 0);
return( 0);
}
/***************************************************************************
Desc: Returns a 64-bit signed integer
***************************************************************************/
FINLINE FLMINT64 fqGetInt64(
FQATOM * pValue)
{
if (pValue->eType == FLM_INT32_VAL)
{
return( (FLMINT64)pValue->val.i32Val);
}
else if( pValue->eType == FLM_INT64_VAL)
{
return( pValue->val.i64Val);
}
else if( pValue->eType == FLM_UINT32_VAL)
{
return( (FLMINT64)pValue->val.ui32Val);
}
else if( pValue->eType == FLM_UINT64_VAL)
{
if( pValue->val.ui64Val <= (FLMUINT64)FLM_MAX_INT64)
{
return( (FLMINT64)pValue->val.ui64Val);
}
}
flmAssert( 0);
return( 0);
}
/***************************************************************************
Desc: Performs the bit and operation
***************************************************************************/
FSTATIC void fqOpUUBitAND(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
if (isNativeNum( pLValue->eType) && isNativeNum( pRValue->eType))
{
pResult->val.ui32Val = pLValue->val.ui32Val & pRValue->val.ui32Val;
pResult->eType = FLM_UINT32_VAL;
}
else
{
pResult->val.ui64Val =
fqGetUInt64( pLValue) & fqGetUInt64( pRValue);
pResult->eType = FLM_UINT64_VAL;
}
}
/***************************************************************************
Desc: Performs the bit or operation
***************************************************************************/
FSTATIC void fqOpUUBitOR(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
if (isNativeNum( pLValue->eType) && isNativeNum( pRValue->eType))
{
pResult->val.ui32Val = pLValue->val.ui32Val | pRValue->val.ui32Val;
pResult->eType = FLM_UINT32_VAL;
}
else
{
pResult->val.ui64Val =
fqGetUInt64( pLValue) | fqGetUInt64( pRValue);
pResult->eType = FLM_UINT64_VAL;
}
}
/***************************************************************************
Desc: Performs the bit xor operation
***************************************************************************/
FSTATIC void fqOpUUBitXOR(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
if (isNativeNum( pLValue->eType) && isNativeNum( pRValue->eType))
{
pResult->val.ui32Val = pLValue->val.ui32Val ^ pRValue->val.ui32Val;
pResult->eType = FLM_UINT32_VAL;
}
else
{
pResult->val.ui64Val =
fqGetUInt64( pLValue) ^ fqGetUInt64( pRValue);
pResult->eType = FLM_UINT64_VAL;
}
}
/***************************************************************************
Desc: Put an unsigned result into a result atom.
***************************************************************************/
FINLINE void setUnsignedResult(
FLMUINT64 ui64Result,
FQATOM * pResult)
{
if (ui64Result <= (FLMUINT64)(FLM_MAX_UINT32))
{
pResult->val.ui32Val = (FLMUINT32)ui64Result;
pResult->eType = FLM_UINT32_VAL;
}
else
{
pResult->val.ui64Val = ui64Result;
pResult->eType = FLM_UINT64_VAL;
}
}
/***************************************************************************
Desc: Put a signed result into a result atom.
***************************************************************************/
FINLINE void setSignedResult(
FLMINT64 i64Result,
FQATOM * pResult)
{
if (i64Result >= (FLMINT64)(FLM_MIN_INT32) &&
i64Result <= (FLMINT64)(FLM_MAX_INT32))
{
pResult->val.i32Val = (FLMINT32)i64Result;
pResult->eType = FLM_INT32_VAL;
}
else
{
pResult->val.i64Val = i64Result;
pResult->eType = FLM_INT64_VAL;
}
}
/***************************************************************************
Desc: Performs the multiply operation
***************************************************************************/
FSTATIC void fqOpUUMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Result = fqGetUInt64( pLValue) * fqGetUInt64( pRValue);
setUnsignedResult( ui64Result, pResult);
}
/***************************************************************************
Desc: Performs the multiply operation
***************************************************************************/
FSTATIC void fqOpUSMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Right < 0)
{
i64Result = (FLMINT64)ui64Left * i64Right;
setSignedResult( i64Result, pResult);
}
else
{
ui64Result = ui64Left * (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs the multiply operation
***************************************************************************/
FSTATIC void fqOpSSMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Left < 0)
{
if (i64Right < 0)
{
if (i64Left == FLM_MIN_INT64)
{
if (i64Right == FLM_MIN_INT64)
{
// The result will actually overflow, but there is
// nothing we can do about that.
ui64Result = FLM_MAX_UINT64;
}
else
{
i64Right = -i64Right;
ui64Result = ((FLMUINT64)(FLM_MAX_INT64) + 1) * (FLMUINT64)i64Right;
}
}
else if (i64Right == FLM_MIN_INT64)
{
i64Left = -i64Left;
ui64Result = (FLMUINT64)i64Left * ((FLMUINT64)(FLM_MAX_INT64) + 1);
}
else
{
i64Left = -i64Left;
i64Right = -i64Right;
ui64Result = (FLMUINT64)i64Left * (FLMUINT64)i64Right;
}
setUnsignedResult( ui64Result, pResult);
}
else
{
i64Result = i64Left * i64Right;
setSignedResult( i64Result, pResult);
}
}
else if (i64Right < 0)
{
i64Result = i64Left * i64Right;
setSignedResult( i64Result, pResult);
}
else
{
ui64Result = (FLMUINT64)i64Left * (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs the multiply operation
***************************************************************************/
FSTATIC void fqOpSUMult(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMINT64 i64Result;
FLMUINT64 ui64Result;
if (i64Left < 0)
{
i64Result = i64Left * (FLMINT64)ui64Right;
setSignedResult( i64Result, pResult);
}
else
{
ui64Result = (FLMUINT64)i64Left * ui64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs the divide operation
***************************************************************************/
FSTATIC void fqOpUUDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMUINT64 ui64Result;
if (ui64Right)
{
ui64Result = ui64Left / ui64Right;
setUnsignedResult( ui64Result, pResult);
}
else
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
}
/***************************************************************************
Desc: Performs the divide operation
***************************************************************************/
FSTATIC void fqOpUSDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Right < 0)
{
if (i64Right == FLM_MIN_INT64)
{
i64Result = -((FLMINT64)(ui64Left / ((FLMUINT64)(FLM_MAX_INT64) + 1)));
}
else
{
i64Right = -i64Right;
i64Result = -((FLMINT64)(ui64Left / (FLMUINT64)i64Right));
}
setSignedResult( i64Result, pResult);
}
else if (!i64Right)
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
else
{
ui64Result = ui64Left / (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs the divide operation
***************************************************************************/
FSTATIC void fqOpSSDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMINT64 i64Result;
if (i64Right)
{
i64Result = i64Left / i64Right;
setSignedResult( i64Result, pResult);
}
else
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
}
/***************************************************************************
Desc: Performs the divide operation
***************************************************************************/
FSTATIC void fqOpSUDiv(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (!ui64Right)
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
else if (i64Left < 0)
{
if (ui64Right >= (FLMUINT64)(FLM_MAX_INT64) + 1)
{
setUnsignedResult( 0, pResult);
}
else
{
i64Result = i64Left / (FLMINT64)ui64Right;
setSignedResult( i64Result, pResult);
}
}
else
{
ui64Result = (FLMUINT64)i64Left / ui64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs the modulo operation
***************************************************************************/
FSTATIC void fqOpUUMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMUINT64 ui64Result;
if (ui64Right)
{
ui64Result = ui64Left % ui64Right;
setUnsignedResult( ui64Result, pResult);
}
else
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
}
/***************************************************************************
Desc: Performs the modulo operation
***************************************************************************/
FSTATIC void fqOpUSMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Right)
{
if (i64Right == FLM_MIN_INT64)
{
i64Result = -((FLMINT64)(ui64Left % ((FLMUINT64)(FLM_MAX_INT64) + 1)));
}
else
{
i64Right = -i64Right;
i64Result = -((FLMINT64)(ui64Left % (FLMUINT64)i64Right));
}
setSignedResult( i64Result, pResult);
}
else if (!i64Right)
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
else
{
ui64Result = ui64Left % (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs the modulo operation
***************************************************************************/
FSTATIC void fqOpSSMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMINT64 i64Result;
if (i64Right)
{
i64Result = i64Left % i64Right;
setSignedResult( i64Result, pResult);
}
else
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
}
/***************************************************************************
Desc: Performs the modulo operation
***************************************************************************/
FSTATIC void fqOpSUMod(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (!ui64Right)
{
pResult->val.ui32Val = 0; // Divide by ZERO case.
pResult->eType = NO_TYPE;
}
else if (i64Left < 0)
{
if (ui64Right >= (FLMUINT64)(FLM_MAX_INT64) + 1)
{
setSignedResult( i64Left, pResult);
}
else
{
i64Result = i64Left % (FLMINT64)ui64Right;
setSignedResult( i64Result, pResult);
}
}
else
{
ui64Result = (FLMUINT64)i64Left % ui64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs an addition operation
***************************************************************************/
FSTATIC void fqOpUUPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Result = fqGetUInt64( pLValue) + fqGetUInt64( pRValue);
setUnsignedResult( ui64Result, pResult);
}
/***************************************************************************
Desc: Performs an addition operation
***************************************************************************/
FSTATIC void fqOpUSPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Right < 0)
{
if (i64Right == FLM_MIN_INT64)
{
if (ui64Left < (FLMUINT64)(FLM_MAX_INT64) + 1)
{
if (!ui64Left)
{
i64Result = FLM_MIN_INT64;
}
else
{
i64Result = -((FLMINT64)((FLMUINT64)(FLM_MAX_INT64) + 1 - ui64Left));
}
setSignedResult( i64Result, pResult);
}
else
{
ui64Result = ui64Left - (FLMUINT64)(FLM_MAX_INT64) - 1;
setUnsignedResult( ui64Result, pResult);
}
}
else
{
i64Right = -i64Right;
if ((FLMUINT64)i64Right > ui64Left)
{
i64Result = -(i64Right - (FLMINT64)ui64Left);
setSignedResult( i64Result, pResult);
}
else
{
ui64Result = ui64Left - (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
}
}
else
{
ui64Result = ui64Left + (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs an addition operation
***************************************************************************/
FSTATIC void fqOpSSPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMINT64 i64Result;
FLMUINT64 ui64Result;
if (i64Left >= 0 && i64Right >= 0)
{
ui64Result = (FLMUINT64)i64Left + (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
else
{
i64Result = i64Left + i64Right;
setSignedResult( i64Result, pResult);
}
}
/***************************************************************************
Desc: Performs an addition operation
***************************************************************************/
FSTATIC void fqOpSUPlus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Left < 0)
{
if (i64Left == FLM_MIN_INT64)
{
if (ui64Right < (FLMUINT64)(FLM_MAX_INT64) + 1)
{
if (!ui64Right)
{
i64Result = FLM_MIN_INT64;
}
else
{
i64Result = -((FLMINT64)((FLMUINT64)(FLM_MAX_INT64) + 1 - ui64Right));
}
setSignedResult( i64Result, pResult);
}
else
{
ui64Result = ui64Right - (FLMUINT64)(FLM_MAX_INT64) - 1;
setUnsignedResult( ui64Result, pResult);
}
}
else
{
i64Left = -i64Left;
if ((FLMUINT64)i64Left > ui64Right)
{
i64Result = -(i64Left - (FLMINT64)ui64Right);
setSignedResult( i64Result, pResult);
}
else
{
ui64Result = ui64Right - (FLMUINT64)i64Left;
setUnsignedResult( ui64Result, pResult);
}
}
}
else
{
ui64Result = ui64Right + (FLMUINT64)i64Left;
setUnsignedResult( ui64Result, pResult);
}
}
/***************************************************************************
Desc: Performs a subtraction operation
***************************************************************************/
FSTATIC void fqOpUUMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if( ui64Left >= ui64Right)
{
ui64Result = ui64Left - ui64Right;
setUnsignedResult( ui64Result, pResult);
}
else
{
i64Result = -((FLMINT64)(ui64Right - ui64Left));
setSignedResult( i64Result, pResult);
}
}
/***************************************************************************
Desc: Performs a subtraction operation
***************************************************************************/
FSTATIC void fqOpUSMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMUINT64 ui64Left = fqGetUInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Right < 0)
{
if (i64Right == FLM_MIN_INT64)
{
ui64Result = ui64Left + (FLMUINT64)FLM_MAX_INT64 + 1;
}
else
{
i64Right = -i64Right;
ui64Result = ui64Left + (FLMUINT64)i64Right;
}
setUnsignedResult( ui64Result, pResult);
}
else
{
if( ui64Left >= (FLMUINT64)i64Right)
{
ui64Result = ui64Left - (FLMUINT64)i64Right;
setUnsignedResult( ui64Result, pResult);
}
else
{
i64Result = -((FLMINT64)(i64Right - (FLMINT64)ui64Left));
setSignedResult( i64Result, pResult);
}
}
}
/***************************************************************************
Desc: Performs a subtraction operation
***************************************************************************/
FSTATIC void fqOpSSMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMINT64 i64Right = fqGetInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Left < 0)
{
if (i64Right >= 0)
{
i64Result = i64Left - i64Right;
setSignedResult( i64Result, pResult);
}
else if (i64Right == FLM_MIN_INT64)
{
if (i64Left == FLM_MIN_INT64)
{
ui64Result = 0;
}
else
{
i64Left = -i64Left;
ui64Result = (FLMUINT64)FLM_MAX_INT64 + 1 - (FLMUINT64)i64Left;
}
setUnsignedResult( ui64Result, pResult);
}
else
{
i64Result = i64Left - i64Right;
setSignedResult( i64Result, pResult);
}
}
else if (i64Right < 0)
{
if (i64Right == FLM_MIN_INT64)
{
ui64Result = (FLMUINT64)i64Left + (FLMUINT64)(FLM_MAX_INT64) + 1;
}
else
{
i64Right = -i64Right;
ui64Result = (FLMUINT64)i64Left + (FLMUINT64)i64Right;
}
setUnsignedResult( ui64Result, pResult);
}
else
{
i64Result = i64Left - i64Right;
setSignedResult( i64Result, pResult);
}
}
/***************************************************************************
Desc: Performs a subtraction operation
***************************************************************************/
FSTATIC void fqOpSUMinus(
FQATOM * pLValue,
FQATOM * pRValue,
FQATOM * pResult)
{
FLMINT64 i64Left = fqGetInt64( pLValue);
FLMUINT64 ui64Right = fqGetUInt64( pRValue);
FLMUINT64 ui64Result;
FLMINT64 i64Result;
if (i64Left < 0)
{
i64Result = i64Left - (FLMINT64)ui64Right;
setSignedResult( i64Result, pResult);
}
else
{
if( (FLMUINT64)i64Left >= ui64Right)
{
ui64Result = (FLMUINT64)i64Left - ui64Right;
setUnsignedResult( ui64Result, pResult);
}
else
{
i64Result = -((FLMINT64)(ui64Right - (FLMUINT64)i64Left));
setSignedResult( i64Result, pResult);
}
}
}
/****************************************************************************
Desc: Evaluates a list of QATOM elements, and returns a complex boolean
based on their contents.
Ret: FLM_TRUE if all elements have nonzero numerics or nonempty buffers.
FLM_FALSE if all contents are zero or empty.
FLM_UNK if any QATOM is of type FLM_UNKNOWN.
Any combination of the preceeding values if their corresponding
criteria are met.
****************************************************************************/
FSTATIC FLMUINT flmCurEvalTrueFalse(
FQATOM * pQAtom)
{
FQATOM * pTmpQAtom;
FLMUINT uiTrueFalse = 0;
for (pTmpQAtom = pQAtom; pTmpQAtom; pTmpQAtom = pTmpQAtom->pNext)
{
if (IS_BUF_TYPE( pTmpQAtom->eType))
{
if (pTmpQAtom->uiBufLen > 0)
{
uiTrueFalse |= FLM_TRUE;
}
else
{
uiTrueFalse |= FLM_FALSE;
}
}
else
{
switch (pTmpQAtom->eType)
{
case FLM_BOOL_VAL:
uiTrueFalse |= pTmpQAtom->val.uiBool;
break;
case FLM_UNKNOWN:
uiTrueFalse |= FLM_UNK;
break;
case FLM_INT32_VAL:
if (pTmpQAtom->val.i32Val)
{
uiTrueFalse |= FLM_TRUE;
}
else
{
uiTrueFalse |= FLM_FALSE;
}
break;
case FLM_INT64_VAL:
if (pTmpQAtom->val.i64Val)
{
uiTrueFalse |= FLM_TRUE;
}
else
{
uiTrueFalse |= FLM_FALSE;
}
break;
case FLM_UINT32_VAL:
if (pTmpQAtom->val.ui32Val)
{
uiTrueFalse |= FLM_TRUE;
}
else
{
uiTrueFalse |= FLM_FALSE;
}
break;
case FLM_UINT64_VAL:
if (pTmpQAtom->val.ui64Val)
{
uiTrueFalse |= FLM_TRUE;
}
else
{
uiTrueFalse |= FLM_FALSE;
}
break;
default:
goto Exit;
}
}
if (uiTrueFalse == FLM_ALL_BOOL)
{
break;
}
}
Exit:
return (uiTrueFalse);
}
/****************************************************************************
Desc: Gets a value from the passed-in record field and stuffs it into the
passed-in FQATOM.
****************************************************************************/
RCODE flmCurGetAtomVal(
FlmRecord * pRecord,
void * pField,
F_Pool * pPool,
QTYPES eFldType,
FQATOM * pResult)
{
RCODE rc = FERR_OK;
FLMUINT uiType = 0;
if (pField)
{
uiType = pRecord->getDataType( pField);
if (uiType == FLM_BLOB_TYPE)
{
rc = RC_SET( FERR_NOT_IMPLEMENTED);
goto Exit;
}
}
switch (eFldType)
{
case FLM_TEXT_VAL:
{
if (!pField)
{
// Default value
pResult->uiBufLen = 0;
pResult->val.pucBuf = NULL;
}
else
{
pResult->uiBufLen = pRecord->getDataLength( pField);
if (pResult->uiBufLen)
{
pResult->val.pucBuf = (FLMBYTE *) pRecord->getDataPtr( pField);
pResult->pFieldRec = pRecord;
}
else
{
if( RC_BAD( rc = pPool->poolAlloc( 1,
(void **)&pResult->val.pucBuf)))
{
rc = RC_SET( FERR_MEM);
break;
}
pResult->val.pucBuf[0] = 0;
}
}
pResult->eType = FLM_TEXT_VAL;
break;
}
case FLM_INT32_VAL:
case FLM_INT64_VAL:
case FLM_UINT32_VAL:
case FLM_UINT64_VAL:
case FLM_REC_PTR_VAL:
{
if (!pField || pRecord->getDataLength( pField) == 0)
{
// Default value
pResult->val.ui32Val = 0;
eFldType = FLM_UINT32_VAL;
}
else if (uiType == FLM_NUMBER_TYPE || uiType == FLM_TEXT_TYPE)
{
if (RC_OK( rc = pRecord->getUINT32( pField, &pResult->val.ui32Val)))
{
eFldType = FLM_UINT32_VAL;
}
else if (rc == FERR_CONV_NUM_OVERFLOW)
{
rc = pRecord->getUINT64( pField, &pResult->val.ui64Val);
eFldType = FLM_UINT64_VAL;
}
else if (rc == FERR_CONV_NUM_UNDERFLOW)
{
if (RC_OK( rc= pRecord->getINT32( pField, &pResult->val.i32Val)))
{
eFldType = FLM_INT32_VAL;
}
else if (rc == FERR_CONV_NUM_UNDERFLOW)
{
rc = pRecord->getINT64( pField, &pResult->val.i64Val);
eFldType = FLM_INT64_VAL;
}
}
}
else if (uiType == FLM_CONTEXT_TYPE)
{
rc = pRecord->getUINT32( pField, &pResult->val.ui32Val);
eFldType = FLM_REC_PTR_VAL;
}
else
{
rc = RC_SET( FERR_CONV_BAD_SRC_TYPE);
}
if (RC_OK( rc))
{
pResult->eType = eFldType;
}
break;
}
case FLM_BINARY_VAL:
{
if (pField)
{
pResult->uiBufLen = pRecord->getDataLength( pField);
}
else
{
pResult->uiBufLen = 0;
}
if (!pResult->uiBufLen)
{
pResult->val.pucBuf = NULL;
}
else
{
pResult->val.pucBuf = (FLMBYTE *) pRecord->getDataPtr( pField);
pResult->pFieldRec = pRecord;
}
pResult->eType = FLM_BINARY_VAL;
break;
}
// No type -- use the type in the passed-in node.
case NO_TYPE:
{
// At this point, if we are attempting to get a default value, but
// don't know the type, it is because both sides of the operand are
// unknown, so we need to return no type.
if (!pField)
{
pResult->eType = NO_TYPE;
}
else
{
switch (uiType)
{
case FLM_TEXT_TYPE:
{
pResult->uiBufLen = pRecord->getDataLength( pField);
if (pResult->uiBufLen)
{
pResult->val.pucBuf = (FLMBYTE *) pRecord->getDataPtr( pField);
pResult->pFieldRec = pRecord;
}
else
{
if( RC_BAD( rc = pPool->poolAlloc( 1,
(void **)&pResult->val.pucBuf)))
{
break;
}
pResult->val.pucBuf[0] = 0;
}
pResult->eType = FLM_TEXT_VAL;
break;
}
case FLM_BINARY_TYPE:
{
if (pField)
{
pResult->uiBufLen = pRecord->getDataLength( pField);
}
else
{
pResult->uiBufLen = 0;
}
if (!pResult->uiBufLen)
{
pResult->val.pucBuf = NULL;
}
else
{
pResult->val.pucBuf =
(FLMBYTE *) pRecord->getDataPtr( pField);
pResult->pFieldRec = pRecord;
}
pResult->eType = FLM_BINARY_VAL;
break;
}
case FLM_NUMBER_TYPE:
{
if (RC_OK( rc = pRecord->getUINT32( pField,
&pResult->val.ui32Val)))
{
pResult->eType = FLM_UINT32_VAL;
}
else if (rc == FERR_CONV_NUM_UNDERFLOW)
{
if (RC_OK( rc = pRecord->getINT32( pField,
&pResult->val.i32Val)))
{
pResult->eType = FLM_INT32_VAL;
}
else if (rc == FERR_CONV_NUM_UNDERFLOW)
{
if (RC_OK( rc = pRecord->getINT64( pField,
&pResult->val.i64Val)))
{
pResult->eType = FLM_INT64_VAL;
}
}
}
else if (rc == FERR_CONV_NUM_OVERFLOW)
{
if (RC_OK( rc = pRecord->getUINT64( pField,
&pResult->val.ui64Val)))
{
pResult->eType = FLM_UINT64_VAL;
}
}
break;
}
case FLM_CONTEXT_TYPE:
{
if (RC_OK( rc = pRecord->getUINT32( pField,
&(pResult->val.ui32Val))))
{
pResult->eType = FLM_UINT32_VAL;
}
break;
}
}
}
break;
}
default:
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
break;
}
}
Exit:
pResult->uiFlags &=
~(FLM_IS_RIGHT_TRUNCATED_DATA | FLM_IS_LEFT_TRUNCATED_DATA);
if (RC_OK( rc) && pField)
{
if (pRecord->isRightTruncated( pField))
{
pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA;
}
if (pRecord->isLeftTruncated( pField))
{
pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA;
}
}
return (rc);
}
/****************************************************************************
Desc: Given a list of FQATOMs containing alternate field paths, finds
those field paths in a compound record and creates a list of FQATOMs
from the contents of those paths.
****************************************************************************/
FSTATIC RCODE flmCurGetAtomFromRec(
FDB * pDb,
F_Pool * pPool,
FQATOM * pTreeAtom,
FlmRecord * pRecord,
QTYPES eFldType,
FLMBOOL bGetAtomVals,
FQATOM * pResult,
FLMBOOL bHaveKey)
{
RCODE rc = FERR_OK;
FQATOM * pTmpResult = NULL;
void * pvField = NULL;
FLMUINT uiLastLevelOneFieldPos = 0;
FLMUINT * puiFldPath;
FLMUINT uiCurrFieldPath[ GED_MAXLVLNUM + 1];
FLMUINT uiFieldLevel;
FLMUINT uiTmp;
FLMUINT uiLeafFldNum;
FLMUINT uiRecFldNum;
FLMBOOL bFound;
FLMBOOL bSavedInvisTrans;
FLMUINT uiResult;
FLMBOOL bPathFromRoot;
FLMBOOL bUseFieldIdLookupTable;
FLMUINT * puiPToCPath;
FLMUINT uiHighestLevel = 0;
FLMUINT uiLevelOneFieldId;
pResult->eType = NO_TYPE;
if (pTreeAtom->val.QueryFld.puiFldPath [0] == FLM_MISSING_FIELD_TAG)
{
goto Exit;
}
if (!pRecord)
{
goto Exit;
}
flmAssert( !pTreeAtom->pNext);
puiFldPath = pTreeAtom->val.QueryFld.puiFldPath;
puiPToCPath = pTreeAtom->val.QueryFld.puiPToCPath;
uiLevelOneFieldId = puiPToCPath [1];
// We are only going to do the path to root optimation if
// the field path is specified as having to be from the root (FLM_ROOTED_PATH)
// and it goes down to at least level 1 in the tree, and our record
// has a field id table in it.
bPathFromRoot = (!bHaveKey &&
(pTreeAtom->uiFlags & FLM_ROOTED_PATH))
? TRUE
: FALSE;
bUseFieldIdLookupTable = (bPathFromRoot &&
pRecord->fieldIdTableEnabled() &&
uiLevelOneFieldId)
? TRUE
: FALSE;
if (*puiFldPath == FLM_RECID_FIELD)
{
pResult->eType = FLM_UINT32_VAL;
pResult->val.ui32Val = (FLMUINT32)pRecord->getID();
goto Exit;
}
pvField = pRecord->root();
uiFieldLevel = 0;
if (bPathFromRoot)
{
// Determine the highest level we need to go down to in the record.
uiHighestLevel = 1;
while (puiPToCPath [uiHighestLevel + 1])
{
uiHighestLevel++;
}
if (puiPToCPath [0] != pRecord->getFieldID( pvField))
{
goto Exit;
}
if (bUseFieldIdLookupTable)
{
if ((pvField =
pRecord->findLevelOneField( uiLevelOneFieldId, FALSE,
&uiLastLevelOneFieldPos)) == NULL)
{
goto Exit;
}
uiCurrFieldPath [0] = puiPToCPath [0];
uiFieldLevel = 1;
}
}
uiLeafFldNum = puiFldPath[ 0];
for (;;)
{
uiRecFldNum = pRecord->getFieldID( pvField);
uiCurrFieldPath[ uiFieldLevel] = uiRecFldNum;
// When we are doing path from root, we only need to traverse
// back up when we are on a field that is exactly at the highest level
// we can go down to in the tree - no need to check any others.
// If we are not doing bPathFromRoot, we check all node paths.
if (uiRecFldNum == uiLeafFldNum &&
(!bPathFromRoot || uiFieldLevel == uiHighestLevel))
{
bFound = TRUE;
// We already know that puiFldPath[0] matches - it is the same
// as uiLeafFldNum. Traverse back up the tree and see if
// the rest of the path matches.
for (uiTmp = 1; puiFldPath[ uiTmp]; uiTmp++)
{
if (!uiFieldLevel)
{
bFound = FALSE;
break;
}
uiFieldLevel--;
if (puiFldPath[ uiTmp] != uiCurrFieldPath[ uiFieldLevel])
{
bFound = FALSE;
break;
}
}
// Found field in proper path. Get the value if requested,
// otherwise set the result to FLM_TRUE and exit. If a
// callback is set, do that first to see if it is REALLY
// found.
if (bFound && pTreeAtom->val.QueryFld.fnGetField)
{
CB_ENTER( pDb, &bSavedInvisTrans);
rc = pTreeAtom->val.QueryFld.fnGetField(
pTreeAtom->val.QueryFld.pvUserData, pRecord,
(HFDB)pDb, pTreeAtom->val.QueryFld.puiFldPath,
FLM_FLD_VALIDATE, NULL, &pvField, &uiResult);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( rc))
{
goto Exit;
}
if (uiResult == FLM_FALSE)
{
bFound = FALSE;
}
else if (uiResult == FLM_UNK)
{
if (bHaveKey)
{
// bHaveKey means we are evaluating a key. There
// should only be one occurrence of the field in the
// key in this case. If the callback does not know
// if the field really exists, we must defer judgement
// on this one until we can fetch the record. Hence,
// we force the result to be UNKNOWN. Note that it
// must be set to UNKNOWN, even if this is a field exists
// predicate (!bGetAtomVals). If we set it to NO_TYPE
// and fall through to exist, it would get converted to
// a FLM_BOOL_VAL of FALSE, which is NOT what we
// want.
pResult->eType = FLM_UNKNOWN;
pResult->uiFlags = pTreeAtom->uiFlags &
~(FLM_IS_RIGHT_TRUNCATED_DATA |
FLM_IS_LEFT_TRUNCATED_DATA);
if (pvField)
{
if (pRecord->isRightTruncated( pvField))
{
pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA;
}
if (pRecord->isLeftTruncated( pvField))
{
pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA;
}
}
// Better not be multiple results in this case because
// we are evaluating a key.
flmAssert( pResult->pNext == NULL);
pResult->pNext = NULL;
goto Exit;
}
else
{
bFound = FALSE;
}
}
}
if (bFound)
{
if (!bGetAtomVals)
{
pResult->eType = FLM_BOOL_VAL;
pResult->val.uiBool = FLM_TRUE;
goto Exit;
}
if (!pTmpResult)
{
pTmpResult = pResult;
}
else if (pTmpResult->eType)
{
if( RC_BAD( rc = pPool->poolCalloc( sizeof( FQATOM),
(void **)&pTmpResult->pNext)))
{
goto Exit;
}
pTmpResult = pTmpResult->pNext;
}
pTmpResult->uiFlags = pTreeAtom->uiFlags;
if ((rc = flmCurGetAtomVal( pRecord, pvField, pPool, eFldType,
pTmpResult)) == FERR_CURSOR_SYNTAX)
{
goto Exit;
}
}
}
// Get the next field to process. If bPathFromRoot is set, we will skip
// any fields that are at too high of levels in the record.
// If bUseFieldIdLookupTable is set, it means
// that when we get back up to level one fields, we should call the
// API to get the next level one field.
for (;;)
{
if ((pvField = pRecord->next( pvField)) == NULL)
{
break;
}
uiFieldLevel = pRecord->getLevel( pvField);
if (!bPathFromRoot)
{
break;
}
if (uiFieldLevel > uiHighestLevel)
{
continue;
}
if (bUseFieldIdLookupTable && uiFieldLevel == 1)
{
pvField = pRecord->nextLevelOneField(
&uiLastLevelOneFieldPos, TRUE);
}
break;
}
// If the end of the record has been reached, and the last field
// value searched for was not found, unlink it from the result list.
if (!pvField)
{
if (pTmpResult && pTmpResult != pResult &&
pTmpResult->eType == NO_TYPE)
{
FQATOM * pTmp;
for (pTmp = pResult;
pTmp && pTmp->pNext != pTmpResult;
pTmp = pTmp->pNext)
{
;
}
pTmp->pNext = NULL;
}
break;
}
}
Exit:
// If no match was found anywhere, set the result to FLM_UNKNOWN if field
// content was requested, or FLM_FALSE if field existence was to be tested.
if (pResult->eType == NO_TYPE)
{
if (bGetAtomVals && !bHaveKey &&
!pTreeAtom->val.QueryFld.fnGetField &&
(pTreeAtom->uiFlags & FLM_USE_DEFAULT_VALUE))
{
rc = flmCurGetAtomVal( pRecord, NULL, pPool, eFldType, pResult);
}
else
{
if (bGetAtomVals || bHaveKey)
{
pResult->eType = FLM_UNKNOWN;
}
else
{
pResult->eType = FLM_BOOL_VAL;
pResult->val.uiBool = FLM_FALSE;
}
pResult->uiFlags = pTreeAtom->uiFlags;
}
}
return( rc);
}
/****************************************************************************
Desc: Iterate to the next occurrance of a field.
****************************************************************************/
FSTATIC RCODE flmFieldIterate(
FDB * pDb,
F_Pool * pPool,
QTYPES eFldType,
FQNODE * pOpCB,
FlmRecord * pRecord,
FLMBOOL bHaveKey,
FLMBOOL bGetAtomVals,
FLMUINT uiAction,
FQATOM * pResult)
{
RCODE rc = FERR_OK;
FlmRecord * pFieldRec = NULL;
void * pField = NULL;
FLMBOOL bSavedInvisTrans;
if (bHaveKey)
{
// bHaveKey is TRUE when we are evaluating a key instead of the
// full record. In this case, it will not be possible for the
// callback function to get all of the values - so we simply return
// unknown, which will be handled by the outside. If the entire
// query evaluates to unknown, FLAIM will fetch the record and
// evaluate the entire thing. This is the safe route to take in this
// case.
pResult->eType = FLM_UNKNOWN;
}
else
{
CB_ENTER( pDb, &bSavedInvisTrans);
rc = pOpCB->pQAtom->val.QueryFld.fnGetField(
pOpCB->pQAtom->val.QueryFld.pvUserData, pRecord, (HFDB) pDb,
pOpCB->pQAtom->val.QueryFld.puiFldPath, uiAction,
&pFieldRec, &pField, NULL);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( rc))
{
goto Exit;
}
if (!pField)
{
if (!bGetAtomVals)
{
pResult->eType = FLM_BOOL_VAL;
pResult->val.uiBool = FLM_FALSE;
}
else
{
if ((pOpCB->pQAtom->uiFlags & FLM_USE_DEFAULT_VALUE) &&
(uiAction == FLM_FLD_FIRST))
{
if (RC_BAD( rc = flmCurGetAtomVal( pFieldRec, NULL, pPool,
eFldType, pResult)))
{
goto Exit;
}
}
else
{
pResult->eType = FLM_UNKNOWN;
}
}
}
else
{
if (!bGetAtomVals)
{
pResult->eType = FLM_BOOL_VAL;
pResult->val.uiBool = FLM_TRUE;
}
else if (RC_BAD( rc = flmCurGetAtomVal( pFieldRec, pField, pPool,
eFldType, pResult)))
{
goto Exit;
}
}
}
Exit:
return (rc);
}
/****************************************************************************
Desc: Performs arithmetic operations on stack element lists.
****************************************************************************/
FSTATIC RCODE flmCurEvalArithOp(
FDB * pDb,
SUBQUERY * pSubQuery,
FlmRecord * pRecord,
FQNODE * pQNode,
QTYPES eOp,
FLMBOOL bGetNewField,
FLMBOOL bHaveKey,
FQATOM * pResult)
{
RCODE rc = FERR_OK;
FQNODE * pTmpQNode;
FQATOM Lhs;
FQATOM Rhs;
FQATOM * pTmpQAtom;
FQATOM * pRhs;
FQATOM * pLhs;
FQATOM * pFirstRhs;
QTYPES eType;
QTYPES eFldType = NO_TYPE;
FLMBOOL bSecondOperand = FALSE;
FQNODE * pRightOpCB = NULL;
FQNODE * pLeftOpCB = NULL;
FQNODE * pOpCB = NULL;
F_Pool * pTmpPool = &pDb->TempPool;
FLMBOOL bSavedInvisTrans;
RCODE TempRc;
if ((pTmpQNode = pQNode->pChild) == NULL)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
return (rc);
}
pLhs = &Lhs;
pRhs = &Rhs;
pLhs->pNext = NULL;
pLhs->pFieldRec = NULL;
pLhs->eType = NO_TYPE;
pLhs->uiBufLen = 0;
pLhs->val.ui32Val = 0;
pRhs->pNext = NULL;
pRhs->pFieldRec = NULL;
pRhs->eType = NO_TYPE;
pRhs->uiBufLen = 0;
pRhs->val.ui32Val = 0;
// Get the two operands (may be multiple values per operand)
pTmpQAtom = pLhs;
Get_Operand:
eType = GET_QNODE_TYPE( pTmpQNode);
if (IS_FLD_CB( eType, pTmpQNode))
{
eType = FLM_CB_FLD;
}
if (IS_VAL( eType))
{
if (bSecondOperand)
{
pRhs = pTmpQNode->pQAtom;
}
else
{
pLhs = pTmpQNode->pQAtom;
}
}
else if (eType == FLM_FLD_PATH || eType == FLM_CB_FLD)
{
if (bSecondOperand)
{
eFldType = pLhs->eType;
if (eType == FLM_CB_FLD)
{
pOpCB = pRightOpCB = pTmpQNode;
}
}
else
{
if (pTmpQNode->pNextSib == NULL)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
eFldType = GET_QNODE_TYPE( pTmpQNode->pNextSib);
if (eType == FLM_CB_FLD)
{
pOpCB = pLeftOpCB = pTmpQNode;
}
}
if (!IS_VAL( eFldType))
{
eFldType = NO_TYPE;
}
if (eType == FLM_CB_FLD)
{
// Get the first occurrence of the field.
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pOpCB,
pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pTmpQAtom)))
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, pTmpPool,
pTmpQNode->pQAtom, pRecord, eFldType, TRUE, pTmpQAtom,
bHaveKey)))
{
goto Exit;
}
}
}
else if (IS_ARITH_OP( eType))
{
// Recursive call
if (RC_BAD( rc = flmCurEvalArithOp( pDb, pSubQuery, pRecord, pTmpQNode,
eType, bGetNewField, bHaveKey, pTmpQAtom)))
{
goto Exit;
}
}
else
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
if (!bSecondOperand)
{
if (eOp == FLM_NEG_OP)
{
pResult = pTmpQAtom;
flmCurDoNeg( pResult);
goto Exit;
}
else
{
if (pTmpQNode->pNextSib == NULL)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
pTmpQNode = pTmpQNode->pNextSib;
pTmpQAtom = pRhs;
bSecondOperand = TRUE;
goto Get_Operand;
}
}
// Now do the operation using our operators
pFirstRhs = pRhs;
pTmpQAtom = pResult;
for (;;)
{
if (pLhs->eType == FLM_UNKNOWN || pRhs->eType == FLM_UNKNOWN)
{
pTmpQAtom->eType = FLM_UNKNOWN;
}
else
{
FQ_OPERATION * fnOp;
FLMUINT uiOffset = 0;
if( IS_UNSIGNED( pLhs->eType))
{
if( IS_UNSIGNED( pRhs->eType))
{
uiOffset = 0;
}
else if( IS_SIGNED( pRhs->eType))
{
uiOffset = 1;
}
else
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
}
else if( IS_SIGNED( pLhs->eType))
{
if( IS_UNSIGNED( pRhs->eType))
{
uiOffset = 2;
}
else if( IS_SIGNED( pRhs->eType))
{
uiOffset = 3;
}
else
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
}
else
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
fnOp = FQ_ArithOpTable[ ((((FLMUINT)eOp) -
FIRST_ARITH_OP) * 4) + uiOffset];
fnOp( pLhs, pRhs, pTmpQAtom);
}
// Doing contextless, do them all - loop through right hand
// operands, then left hand operands.
//
// Get the next right hand operand.
if (!pRightOpCB)
{
pRhs = pRhs->pNext;
}
else if (pRhs->eType == FLM_UNKNOWN)
{
pRhs = NULL;
}
else
{
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pRightOpCB,
pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pRhs)))
{
goto Exit;
}
if (pRhs->eType == FLM_UNKNOWN)
{
pRhs = NULL;
}
}
// If no more right hand side, get the next left hand side, and
// reset the right hand side.
if (!pRhs)
{
if (!pLeftOpCB)
{
pLhs = pLhs->pNext;
}
else if (pLhs->eType == FLM_UNKNOWN)
{
pLhs = NULL;
}
else
{
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType,
pLeftOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pLhs)))
{
goto Exit;
}
if (pLhs->eType == FLM_UNKNOWN)
{
pLhs = NULL;
}
}
if (!pLhs)
{
break;
}
// Reset the right hand side back to first.
if (pRightOpCB)
{
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType,
pRightOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pRhs)))
{
goto Exit;
}
}
else
{
pRhs = pFirstRhs;
}
}
// Set up for next result
if( RC_BAD( rc = pTmpPool->poolCalloc( sizeof( FQATOM),
(void **)&pTmpQAtom->pNext)))
{
goto Exit;
}
pTmpQAtom = pTmpQAtom->pNext;
}
Exit:
// Clean up any field callbacks.
if (pLeftOpCB)
{
CB_ENTER( pDb, &bSavedInvisTrans);
TempRc = pLeftOpCB->pQAtom->val.QueryFld.fnGetField(
pLeftOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb,
pLeftOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL,
NULL, NULL);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( TempRc))
{
if (RC_OK( rc))
{
rc = TempRc;
}
}
}
if (pRightOpCB)
{
CB_ENTER( pDb, &bSavedInvisTrans);
TempRc = pRightOpCB->pQAtom->val.QueryFld.fnGetField(
pRightOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb,
pRightOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL,
NULL, NULL);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( TempRc))
{
if (RC_OK( rc))
{
rc = TempRc;
}
}
}
return (rc);
}
/****************************************************************************
Desc: Performs a comparison operation on two operands, one or both of
which can be FLM_UNKNOWN.
****************************************************************************/
void flmCompareOperands(
FLMUINT uiLang,
FQATOM * pLhs,
FQATOM * pRhs,
QTYPES eOp,
FLMBOOL bResolveUnknown,
FLMBOOL bForEvery,
FLMBOOL bNotted,
FLMBOOL bHaveKey,
FLMUINT * puiTrueFalse)
{
if (pLhs->eType == FLM_UNKNOWN || pRhs->eType == FLM_UNKNOWN)
{
// If we are not resolving predicates with unknown operands, return
// FLM_UNK.
if (bHaveKey || !bResolveUnknown)
{
*puiTrueFalse = FLM_UNK;
}
else if (bNotted)
{
// If bNotted is TRUE, the result will be inverted on the
// outside, so we need to set it to the opposite of what we want
// it to ultimately be.
*puiTrueFalse = (bForEvery ? FLM_FALSE : FLM_TRUE);
}
else
{
*puiTrueFalse = (bForEvery ? FLM_TRUE : FLM_FALSE);
}
}
// At this point, both operands are known to be present. The
// comparison will therefore be performed according to the operator
// specified.
else
{
switch (eOp)
{
case FLM_EQ_OP:
{
// OPTIMIZATION: for UINT32 compares avoid func call by doing
// compare here!
if (pLhs->eType == FLM_UINT32_VAL && pRhs->eType == FLM_UINT32_VAL)
{
*puiTrueFalse =
(FQ_COMPARE( pLhs->val.ui32Val, pRhs->val.ui32Val) == 0)
? FLM_TRUE : FLM_FALSE;
}
else
{
*puiTrueFalse =
(flmCurDoRelationalOp( pLhs, pRhs, uiLang) == 0)
? FLM_TRUE : FLM_FALSE;
}
break;
}
case FLM_MATCH_OP:
{
if ((pLhs->uiFlags & FLM_COMP_WILD) ||
(pRhs->uiFlags & FLM_COMP_WILD))
{
*puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, FALSE, FALSE);
}
else
{
*puiTrueFalse =
(flmCurDoRelationalOp( pLhs, pRhs, uiLang) == 0)
? FLM_TRUE : FLM_FALSE;
}
break;
}
case FLM_MATCH_BEGIN_OP:
{
*puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, FALSE, TRUE);
break;
}
case FLM_MATCH_END_OP:
{
*puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, TRUE, FALSE);
break;
}
case FLM_NE_OP:
{
*puiTrueFalse =
(flmCurDoRelationalOp( pLhs, pRhs, uiLang) != 0)
? FLM_TRUE : FLM_FALSE;
break;
}
case FLM_LT_OP:
{
*puiTrueFalse =
(flmCurDoRelationalOp( pLhs, pRhs, uiLang) < 0)
? FLM_TRUE : FLM_FALSE;
break;
}
case FLM_LE_OP:
{
*puiTrueFalse =
(flmCurDoRelationalOp( pLhs, pRhs, uiLang) <= 0)
? FLM_TRUE : FLM_FALSE;
break;
}
case FLM_GT_OP:
{
*puiTrueFalse =
(flmCurDoRelationalOp( pLhs, pRhs, uiLang) > 0)
? FLM_TRUE : FLM_FALSE;
break;
}
case FLM_GE_OP:
{
*puiTrueFalse =
(flmCurDoRelationalOp( pLhs, pRhs, uiLang) >= 0)
? FLM_TRUE : FLM_FALSE;
break;
}
case FLM_CONTAINS_OP:
{
*puiTrueFalse = flmCurDoContainsOp( pLhs, pRhs, uiLang);
break;
}
default:
{
// Syntax error.
*puiTrueFalse = 0;
flmAssert( 0);
break;
}
}
}
}
/****************************************************************************
Desc: Performs relational operations on stack elements.
****************************************************************************/
RCODE flmCurEvalCompareOp(
FDB * pDb,
SUBQUERY * pSubQuery,
FlmRecord * pRecord,
FQNODE * pQNode,
QTYPES eOp,
FLMBOOL bHaveKey,
FQATOM * pResult)
{
RCODE rc = FERR_OK;
FQNODE * pTmpQNode;
FQATOM * pTmpQAtom;
FQATOM * pLhs;
FQATOM * pRhs;
FQATOM * pFirstRhs;
FQATOM Lhs;
FQATOM Rhs;
QTYPES wTmpOp = eOp;
QTYPES eType;
QTYPES eFldType = NO_TYPE;
FLMUINT uiTrueFalse = 0;
FLMBOOL bSecondOperand;
FLMBOOL bSwitchOperands = FALSE;
FLMBOOL bGetNewField = FALSE;
FLMBOOL bRightTruncated = FALSE;
FLMBOOL bNotted = (pQNode->uiStatus & FLM_NOTTED) ? TRUE : FALSE;
FLMBOOL bResolveUnknown = (pQNode->uiStatus & FLM_RESOLVE_UNK) ? TRUE : FALSE;
FLMBOOL bForEvery = (pQNode->uiStatus & FLM_FOR_EVERY) ? TRUE : FALSE;
FQNODE * pRightOpCB = NULL;
FQNODE * pLeftOpCB = NULL;
FQNODE * pOpCB = NULL;
RCODE TempRc;
FLMBOOL bSavedInvisTrans;
F_Pool * pTmpPool = &pDb->TempPool;
void * pvMark = pTmpPool->poolMark();
pResult->eType = FLM_BOOL_VAL;
pResult->pNext = NULL;
pResult->val.uiBool = 0;
if (pQNode->pChild == NULL)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
pLhs = &Lhs;
pRhs = &Rhs;
pTmpQNode = pQNode->pChild;
bSecondOperand = FALSE;
f_memset( &Lhs, 0, sizeof(FQATOM));
f_memset( &Rhs, 0, sizeof(FQATOM));
pLhs->eType = pRhs->eType = NO_TYPE;
// Get the two operands from the stack or passed-in record node
pTmpQAtom = pLhs;
Get_Operand:
eType = GET_QNODE_TYPE( pTmpQNode);
if (IS_FLD_CB( eType, pTmpQNode))
{
eType = FLM_CB_FLD;
}
if (IS_VAL( eType))
{
if (bSecondOperand)
{
pRhs = pTmpQNode->pQAtom;
}
else
{
pLhs = pTmpQNode->pQAtom;
bSwitchOperands = TRUE;
}
}
else if (eType == FLM_FLD_PATH || eType == FLM_CB_FLD)
{
if (bSecondOperand)
{
eFldType = pLhs->eType;
if (eType == FLM_CB_FLD)
{
pOpCB = pRightOpCB = pTmpQNode;
}
}
else
{
if (pTmpQNode->pNextSib == NULL)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
eFldType = GET_QNODE_TYPE( pTmpQNode->pNextSib);
if (eType == FLM_CB_FLD)
{
pOpCB = pLeftOpCB = pTmpQNode;
}
}
if (!IS_VAL( eFldType))
{
eFldType = NO_TYPE;
}
if (eType == FLM_CB_FLD)
{
// Get the first occurrence of the field.
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pOpCB,
pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pTmpQAtom)))
{
goto Exit;
}
if (pTmpQAtom->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA)
{
bRightTruncated = TRUE;
}
}
else
{
if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, pTmpPool,
pTmpQNode->pQAtom, pRecord, eFldType, TRUE, pTmpQAtom,
bHaveKey)))
{
goto Exit;
}
if (pTmpQAtom->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA)
{
bRightTruncated = TRUE;
}
}
// Check to see if this field is a substring field in the index. If
// it is, and it is not the first substring value in the field, and
// we are doing a match begin or match operator, return FLM_FALSE -
// we cannot evaluate anything except first substrings in these two
// cases. NOTE: If we are evaluating a key and this is a callback
// field, we don't need to worry about this condition, because the
// CB field will have been set up to return unknown.
if (bHaveKey &&
(pTmpQAtom->uiFlags & FLM_IS_LEFT_TRUNCATED_DATA) &&
(eOp == FLM_MATCH_OP || eOp == FLM_MATCH_BEGIN_OP))
{
pResult->val.uiBool = FLM_FALSE;
goto Exit;
}
}
else if (IS_ARITH_OP( eType))
{
if (RC_BAD( rc = flmCurEvalArithOp( pDb, pSubQuery, pRecord, pTmpQNode,
eType, bGetNewField, bHaveKey, pTmpQAtom)))
{
goto Exit;
}
}
else
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
if (!bSecondOperand)
{
if (pTmpQNode->pNextSib == NULL)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
pTmpQNode = pTmpQNode->pNextSib;
pTmpQAtom = pRhs;
bSecondOperand = TRUE;
goto Get_Operand;
}
// If necessary, reverse the operator to render the expression in the
// form <field><op><value>.
if (bSwitchOperands)
{
if (REVERSIBLE( eOp))
{
wTmpOp = DO_REVERSE( eOp);
pLhs = &Rhs;
pRhs = &Lhs;
}
else
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
}
// Now do the operation using our operators.
pFirstRhs = pRhs;
for (;;)
{
FLMBOOL bDoComp = TRUE;
// If this key piece is truncated, and the selection criteria can't
// be evaluated as a result, read the record and start again. NOTE:
// this will only happen if the field type is text or binary.
if (bHaveKey &&
bRightTruncated &&
pRhs->eType != FLM_UNKNOWN &&
pLhs->eType != FLM_UNKNOWN)
{
// VISIT: We should be optimized to flunk or pass text compares.
// The problems come with comparing only up to the first
// wildcard.
if (pLhs->eType != FLM_BINARY_VAL)
{
uiTrueFalse = FLM_UNK;
}
else
{
FLMINT iCompVal;
// We better only compare binary types here.
flmAssert( pRhs->eType == FLM_BINARY_VAL);
iCompVal = f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf,
f_min( pLhs->uiBufLen, pRhs->uiBufLen));
if (!iCompVal)
{
// Lhs is the truncated key. If its length is <= to the
// length of the Rhs, comparison must continue by fetching
// the record. So, we set uiTrueFalse to FLM_UNK.
// Otherwise, we know that the Lhs length is greater than
// the Rhs, so we are able to complete the comparison even
// though the key is truncated.
if (pLhs->uiBufLen <= pRhs->uiBufLen)
{
uiTrueFalse = FLM_UNK;
}
else
{
iCompVal = 1;
}
}
// iCompVal == 0 has been handled above. This means that
// uiTrueFalse has been set to FLM_UNK.
if (iCompVal)
{
switch (eOp)
{
case FLM_NE_OP:
{
// We know that iCompVal != 0
uiTrueFalse = FLM_TRUE;
break;
}
case FLM_GT_OP:
case FLM_GE_OP:
{
uiTrueFalse = (iCompVal > 0) ? FLM_TRUE : FLM_FALSE;
break;
}
case FLM_LT_OP:
case FLM_LE_OP:
{
uiTrueFalse = (iCompVal < 0) ? FLM_TRUE : FLM_FALSE;
break;
}
case FLM_EQ_OP:
default:
{
// We know that iCompVal != 0
uiTrueFalse = FLM_FALSE;
break;
}
}
}
bDoComp = FALSE;
}
}
else
{
flmCompareOperands( pSubQuery->uiLanguage, pLhs, pRhs, eOp,
bResolveUnknown, bForEvery, bNotted, bHaveKey,
&uiTrueFalse);
}
if (bNotted)
{
uiTrueFalse = (uiTrueFalse == FLM_TRUE)
? FLM_FALSE
: (uiTrueFalse == FLM_FALSE)
? FLM_TRUE
: FLM_UNK;
}
// For index keys - validate that the field is correct if the
// compare returned true. Otherwise, set the result to unknown.
// VISIT: This will not work for index keys that have more than one
// field that needs to be validated.
if (bDoComp && eType == FLM_FLD_PATH &&
uiTrueFalse == FLM_TRUE && bHaveKey)
{
FQATOM * pTreeAtom = pTmpQNode->pQAtom;
FLMUINT uiResult;
void * pField = NULL;
CB_ENTER( pDb, &bSavedInvisTrans);
rc = pTreeAtom->val.QueryFld.fnGetField(
pTreeAtom->val.QueryFld.pvUserData, pRecord, (HFDB) pDb,
pTreeAtom->val.QueryFld.puiFldPath, FLM_FLD_VALIDATE, NULL,
&pField, &uiResult);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( rc))
{
goto Exit;
}
else if (uiResult == FLM_UNK)
{
uiTrueFalse = FLM_UNK;
}
else if (uiResult == FLM_FALSE)
{
uiTrueFalse = FLM_FALSE;
}
}
pResult->val.uiBool = uiTrueFalse;
// Doing contextless, see if we need to process any more. If the
// FOR EVERY flag is TRUE (universal quantifier), we quit when we
// see a FALSE. If the FOR EVERY flag is FALSE (existential
// quantifier), we quit when we see a TRUE.
if ((bForEvery && uiTrueFalse == FLM_FALSE) ||
(!bForEvery && uiTrueFalse == FLM_TRUE))
{
break;
}
// Get the next right hand operand.
if (!pRightOpCB)
{
pRhs = pRhs->pNext;
}
else if (pRhs->eType == FLM_UNKNOWN)
{
pRhs = NULL;
}
else
{
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pRightOpCB,
pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pRhs)))
{
goto Exit;
}
if (pRhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA)
{
bRightTruncated = TRUE;
}
if (pRhs->eType == FLM_UNKNOWN)
{
pRhs = NULL;
}
}
// If no more right hand side, get the next left hand side, and
// reset the right hand side.
if (!pRhs)
{
if (!pLeftOpCB)
{
pLhs = pLhs->pNext;
}
else if (pLhs->eType == FLM_UNKNOWN)
{
pLhs = NULL;
}
else
{
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType,
pLeftOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pLhs)))
{
goto Exit;
}
if (pLhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA)
{
bRightTruncated = TRUE;
}
if (pLhs->eType == FLM_UNKNOWN)
{
pLhs = NULL;
}
}
if (!pLhs)
{
break;
}
// Reset the right hand side to the first.
if (pRightOpCB)
{
if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType,
pRightOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pRhs)))
{
goto Exit;
}
if (pRhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA)
{
bRightTruncated = TRUE;
}
}
else
{
pRhs = pFirstRhs;
}
}
}
Exit:
// Clean up any field callbacks.
if (pLeftOpCB)
{
CB_ENTER( pDb, &bSavedInvisTrans);
TempRc = pLeftOpCB->pQAtom->val.QueryFld.fnGetField(
pLeftOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb,
pLeftOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL,
NULL, NULL);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( TempRc))
{
if (RC_OK( rc))
{
rc = TempRc;
}
}
}
if (pRightOpCB)
{
CB_ENTER( pDb, &bSavedInvisTrans);
TempRc = pRightOpCB->pQAtom->val.QueryFld.fnGetField(
pRightOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb,
pRightOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL,
NULL, NULL);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( TempRc))
{
if (RC_OK( rc))
{
rc = TempRc;
}
}
}
pTmpPool->poolReset( pvMark);
return (rc);
}
/****************************************************************************
Desc: Performs logical AND or OR operations
****************************************************************************/
FSTATIC RCODE flmCurEvalLogicalOp(
FDB * pDb,
SUBQUERY * pSubQuery,
FlmRecord * pRecord,
FQNODE * pQNode,
QTYPES eOp,
FLMBOOL bHaveKey,
FQATOM * pResult)
{
RCODE rc = FERR_OK;
FQATOM TmpQAtom;
FQNODE * pTmpQNode;
FQATOM * pTmpQAtom;
QTYPES eType;
FLMBOOL bSavedInvisTrans;
FLMUINT uiTrueFalse;
RCODE TempRc;
pResult->eType = FLM_BOOL_VAL;
pResult->pNext = NULL;
pResult->val.uiBool = 0;
if (pQNode->pChild == NULL)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
FLM_SET_RESULT( pQNode->uiStatus, 0);
pTmpQNode = pQNode->pChild;
Get_Operand:
// Get the operand to process
pTmpQAtom = &TmpQAtom;
pTmpQAtom->pNext = NULL;
pTmpQAtom->pFieldRec = NULL;
pTmpQAtom->eType = NO_TYPE;
pTmpQAtom->uiBufLen = 0;
pTmpQAtom->val.ui32Val = 0;
eType = GET_QNODE_TYPE( pTmpQNode);
if (IS_FLD_CB( eType, pTmpQNode))
{
eType = FLM_CB_FLD;
}
if (IS_VAL( eType))
{
pTmpQAtom = pTmpQNode->pQAtom;
}
else if (eType == FLM_CB_FLD)
{
// Get the first occurrence of the field.
if (RC_OK( rc = flmFieldIterate( pDb, &pDb->TempPool, NO_TYPE, pTmpQNode,
pRecord, bHaveKey, FALSE, FLM_FLD_FIRST, pTmpQAtom)))
{
if (pTmpQNode->uiStatus & FLM_NOTTED &&
pTmpQAtom->eType == FLM_BOOL_VAL)
{
pTmpQAtom->val.uiBool = (pTmpQAtom->val.uiBool == FLM_TRUE)
? FLM_FALSE
: FLM_TRUE;
}
}
CB_ENTER( pDb, &bSavedInvisTrans);
TempRc = pTmpQNode->pQAtom->val.QueryFld.fnGetField(
pTmpQNode->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb,
pTmpQNode->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL,
NULL, NULL);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( TempRc) && RC_OK( rc))
{
rc = TempRc;
}
if (RC_BAD( rc))
{
goto Exit;
}
}
else if (eType == FLM_FLD_PATH)
{
if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, &pDb->TempPool,
pTmpQNode->pQAtom, pRecord, NO_TYPE, FALSE, pTmpQAtom, bHaveKey)))
{
goto Exit;
}
// NOTE: pTmpQAtom could come back from this as an UNKNOWN now,
// even though we are testing for field existence. This could happen
// when we are testing a key and we have a callback, but the
// callback cannot tell if the field instance is actually present or
// not.
if ((pTmpQNode->uiStatus & FLM_NOTTED) &&
(pTmpQAtom->eType == FLM_BOOL_VAL))
{
pTmpQAtom->val.uiBool = (pTmpQAtom->val.uiBool == FLM_TRUE)
? FLM_FALSE
: FLM_TRUE;
}
}
else if (IS_LOG_OP( eType))
{
// Traverse down the tree.
pQNode = pTmpQNode;
eOp = eType;
FLM_SET_RESULT( pQNode->uiStatus, 0);
pTmpQNode = pTmpQNode->pChild;
goto Get_Operand;
}
else if (IS_COMPARE_OP( eType))
{
if (RC_BAD( rc = flmCurEvalCompareOp( pDb, pSubQuery, pRecord, pTmpQNode,
eType, bHaveKey, pTmpQAtom)))
{
goto Exit;
}
}
else if (eType == FLM_USER_PREDICATE)
{
if (bHaveKey)
{
// Don't want to do the callback if we only have a key - because
// the callback won't have access to all of the values from here.
// The safe thing is to just return unknown.
pResult->eType = FLM_UNKNOWN;
goto Exit;
}
else
{
CB_ENTER( pDb, &bSavedInvisTrans);
rc = pTmpQNode->pQAtom->val.pPredicate->testRecord(
(HFDB) pDb, pRecord, pRecord->getID(), &pTmpQAtom->val.uiBool);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( rc))
{
goto Exit;
}
pTmpQAtom->eType = FLM_BOOL_VAL;
}
}
else
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
// See what our TRUE/FALSE result is.
uiTrueFalse = flmCurEvalTrueFalse( pTmpQAtom);
// Traverse back up the tree, ORing or ANDing or NOTing this result as
// necessary.
for (;;)
{
// If ANDing and we have a FALSE result or ORing and we have a TRUE
// result, the result can simply be propagated up the tree.
if ((eOp == FLM_AND_OP && uiTrueFalse == FLM_FALSE) ||
(eOp == FLM_OR_OP && uiTrueFalse == FLM_TRUE))
{
// We are done if we can go no higher in the tree.
pTmpQNode = pQNode;
if ((pQNode = pQNode->pParent) == NULL)
{
break;
}
eOp = GET_QNODE_TYPE( pQNode);
}
else if (pTmpQNode->pNextSib)
{
// Can only be one operand of a NOT operator.
flmAssert( eOp != FLM_NOT_OP);
// Save the left-hand side result into pQNode->uiStatus
FLM_SET_RESULT( pQNode->uiStatus, uiTrueFalse);
pTmpQNode = pTmpQNode->pNextSib;
goto Get_Operand;
}
else // Processing results of right hand operand
{
FLMUINT uiRhs;
if (eOp == FLM_AND_OP)
{
// FALSE case for AND operator has already been handled up
// above.
flmAssert( uiTrueFalse != FLM_FALSE);
// AND the results from the left-hand side. Get left-hand
// side result from pQNode.
uiRhs = uiTrueFalse;
uiTrueFalse = FLM_GET_RESULT( pQNode->uiStatus);
// Perform logical AND operation.
if (uiRhs & FLM_FALSE)
{
uiTrueFalse |= FLM_FALSE;
}
if (uiRhs & FLM_UNK)
{
uiTrueFalse |= FLM_UNK;
}
// If both left hand side and right hand side do not have
// FLM_TRUE set, we must turn it off.
if ((uiTrueFalse & FLM_TRUE) && (!(uiRhs & FLM_TRUE)))
{
uiTrueFalse &= (~(FLM_TRUE));
}
}
else if (eOp == FLM_OR_OP)
{
// TRUE case for OR operator better have been handled up
// above.
flmAssert( uiTrueFalse != FLM_TRUE);
// OR the results from the left hand side. Get left-hand side
// result from pQNode.
uiRhs = uiTrueFalse;
uiTrueFalse = FLM_GET_RESULT( pQNode->uiStatus);
// Perform logical OR operation.
if (uiRhs & FLM_TRUE)
{
uiTrueFalse |= FLM_TRUE;
}
if (uiRhs & FLM_UNK)
{
uiTrueFalse |= FLM_UNK;
}
// If both left hand side and right hand side do not have
// FLM_FALSE set, we must turn it off.
if ((uiTrueFalse & FLM_FALSE) && (!(uiRhs & FLM_FALSE)))
{
uiTrueFalse &= (~(FLM_FALSE));
}
}
else // (eOp == FLM_NOT_OP)
{
flmAssert( eOp == FLM_NOT_OP);
// NOT the result
if (uiTrueFalse == FLM_TRUE)
{
uiTrueFalse = FLM_FALSE;
}
else if (uiTrueFalse == FLM_FALSE)
{
uiTrueFalse = FLM_TRUE;
}
else if (uiTrueFalse == (FLM_UNK | FLM_TRUE))
{
uiTrueFalse = FLM_FALSE | FLM_UNK;
}
else if (uiTrueFalse == (FLM_UNK | FLM_FALSE))
{
uiTrueFalse = FLM_TRUE | FLM_UNK;
}
}
// Traverse back up to the parent with this result.
pTmpQNode = pQNode;
// We are done if we are at the top of the tree.
if ((pQNode = pQNode->pParent) == NULL)
{
break;
}
eOp = GET_QNODE_TYPE( pQNode);
}
}
// At this point, we are done, because there is no higher to traverse
// back up in the tree.
pResult->val.uiBool = uiTrueFalse;
Exit:
return (rc);
}
/****************************************************************************
Desc: Checks a record that has been retrieved from the database
to see if it matches the criteria specified in the query
stack.
****************************************************************************/
RCODE flmCurEvalCriteria(
CURSOR * pCursor,
SUBQUERY * pSubQuery,
FlmRecord * pRecord,
FLMBOOL bHaveKey,
FLMUINT * puiResult)
{
RCODE rc = FERR_OK;
FQATOM Result;
QTYPES eType;
FDB * pDb = pCursor->pDb;
FQNODE * pQNode;
void * pTmpMark = pDb->TempPool.poolMark();
FLMUINT uiResult = 0;
FQNODE * pOpCB = NULL;
RCODE TempRc;
// By definition, a NULL record doesn't match selection criteria.
if (!pRecord)
{
uiResult = FLM_FALSE;
goto Exit;
}
// Record's container ID must match the cursor's
if (pRecord->getContainerID() != pCursor->uiContainer)
{
uiResult = FLM_FALSE;
goto Exit;
}
if (!pSubQuery->pTree)
{
uiResult = FLM_TRUE;
goto Exit;
}
// First check the record type if necessary, then verify that there
// are search criteria to match against.
if (pCursor->uiRecType)
{
void * pField = pRecord->root();
if (!pField || pCursor->uiRecType != pRecord->getFieldID( pField))
{
uiResult = FLM_FALSE;
goto Exit;
}
}
pQNode = pSubQuery->pTree;
f_memset( &Result, 0, sizeof(FQATOM));
eType = GET_QNODE_TYPE( pQNode);
if (IS_FLD_CB( eType, pQNode))
{
eType = FLM_CB_FLD;
}
if (IS_VAL( eType))
{
uiResult = flmCurEvalTrueFalse( pQNode->pQAtom);
}
else if (eType == FLM_USER_PREDICATE)
{
if (bHaveKey)
{
// Don't want to do the callback if we only have a key - because
// the callback won't have access to all of the values from here.
// The safe thing is to just return unknown.
uiResult = FLM_UNK;
rc = FERR_OK;
}
else
{
FLMBOOL bSavedInvisTrans;
CB_ENTER( pDb, &bSavedInvisTrans);
rc = pQNode->pQAtom->val.pPredicate->testRecord(
(HFDB) pDb, pRecord, pRecord->getID(), &uiResult);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( rc))
{
goto Exit;
}
}
}
else
{
if (eType == FLM_CB_FLD)
{
// Get the first occurrence of the field.
pOpCB = pQNode;
if (RC_BAD( rc = flmFieldIterate( pDb, &pDb->TempPool, NO_TYPE, pQNode,
pRecord, bHaveKey, FALSE, FLM_FLD_FIRST, &Result)))
{
goto Exit;
}
if (pQNode->uiStatus & FLM_NOTTED && Result.eType == FLM_BOOL_VAL)
{
Result.val.uiBool = (Result.val.uiBool == FLM_TRUE)
? FLM_FALSE
: FLM_TRUE;
}
}
else if (eType == FLM_FLD_PATH)
{
if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, &pDb->TempPool,
pQNode->pQAtom, pRecord, NO_TYPE, FALSE, &Result,
bHaveKey)))
{
goto Exit;
}
// NOTE: Result could come back from this as an UNKNOWN now,
// even though we are testing for field existence. This could
// happen when we are testing a key and we have a callback, but
// the callback cannot tell if the field instance is actually
// present or not.
if ((pQNode->uiStatus & FLM_NOTTED) && (Result.eType == FLM_BOOL_VAL))
{
Result.val.uiBool = (Result.val.uiBool == FLM_TRUE)
? FLM_FALSE
: FLM_TRUE;
}
}
else if (IS_LOG_OP( eType))
{
if (RC_BAD( rc = flmCurEvalLogicalOp( pDb, pSubQuery, pRecord, pQNode,
eType, bHaveKey, &Result)))
{
goto Exit;
}
}
else if (IS_COMPARE_OP( eType))
{
if (RC_BAD( rc = flmCurEvalCompareOp( pDb, pSubQuery, pRecord, pQNode,
eType, bHaveKey, &Result)))
{
goto Exit;
}
}
else
{
uiResult = FLM_FALSE;
rc = RC_SET( FERR_CURSOR_SYNTAX);
goto Exit;
}
uiResult = flmCurEvalTrueFalse( &Result);
if (!bHaveKey && uiResult == FLM_UNK)
{
uiResult = FLM_FALSE;
}
}
Exit:
if (rc == FERR_EOF_HIT)
{
rc = FERR_OK;
}
// Clean up any field callbacks.
if (pOpCB)
{
FLMBOOL bSavedInvisTrans;
CB_ENTER( pDb, &bSavedInvisTrans);
TempRc = pOpCB->pQAtom->val.QueryFld.fnGetField(
pOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb,
pOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL, NULL,
NULL);
CB_EXIT( pDb, bSavedInvisTrans);
if (RC_BAD( TempRc))
{
if (RC_OK( rc))
{
rc = TempRc;
}
}
}
pDb->TempPool.poolReset( pTmpMark);
*puiResult = uiResult;
return (rc);
}
/****************************************************************************
Desc:
****************************************************************************/
FSTATIC RCODE flmCurDoNeg(
FQATOM * pResult)
{
RCODE rc = FERR_OK;
FQATOM * pTmpQAtom;
// Perform operation on list according to operand types
for (pTmpQAtom = pResult; pTmpQAtom; pTmpQAtom = pTmpQAtom->pNext)
{
if (IS_UNSIGNED( pTmpQAtom->eType))
{
if (isNativeNum( pTmpQAtom->eType))
{
if (pTmpQAtom->val.ui32Val >= (FLMUINT)(FLM_MAX_INT32) + 1)
{
pTmpQAtom->eType = NO_TYPE;
}
else
{
pTmpQAtom->val.i32Val = -((FLMINT32)(pTmpQAtom->val.ui32Val));
pTmpQAtom->eType = FLM_INT32_VAL;
}
}
else
{
if (pTmpQAtom->val.ui64Val >= (FLMUINT64)(FLM_MAX_INT64) + 1)
{
pTmpQAtom->eType = NO_TYPE;
}
else
{
pTmpQAtom->val.i64Val = -((FLMINT64)(pTmpQAtom->val.ui64Val));
pTmpQAtom->eType = FLM_INT64_VAL;
}
}
}
else if (IS_SIGNED( pTmpQAtom->eType))
{
if (isNativeNum( pTmpQAtom->eType))
{
pTmpQAtom->val.i32Val *= -1;
}
else
{
pTmpQAtom->val.i64Val *= -1;
}
}
else if (pTmpQAtom->eType != FLM_UNKNOWN)
{
rc = RC_SET( FERR_CURSOR_SYNTAX);
break;
}
}
return (rc);
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT flmCurDoMatchOp(
FQATOM * pLhs,
FQATOM * pRhs,
FLMUINT uiLang,
FLMBOOL bLeadingWildCard,
FLMBOOL bTrailingWildCard)
{
FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags;
FLMUINT uiTrueFalse = 0;
// Verify operand types - non-text and non-binary return false
if (!IS_BUF_TYPE( pLhs->eType) || !IS_BUF_TYPE( pRhs->eType))
{
goto Exit;
}
// If one of the operands is binary, simply do a byte comparison of the
// two values without regard to case or wildcards.
if ((pLhs->eType == FLM_BINARY_VAL) || (pRhs->eType == FLM_BINARY_VAL))
{
FLMUINT uiLen1;
FLMUINT uiLen2;
uiLen1 = pLhs->uiBufLen;
uiLen2 = pRhs->uiBufLen;
flmAssert( !bLeadingWildCard);
if ((bTrailingWildCard) && (uiLen2 > uiLen1))
{
uiLen2 = uiLen1;
}
uiTrueFalse = (FLMUINT)
(
(
(uiLen1 == uiLen2) &&
(f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, uiLen1) == 0)
) ? (FLMUINT) FLM_TRUE : (FLMUINT) FLM_FALSE
);
goto Exit;
}
// If wildcards are set, do a string search, first making necessary
// adjustments for case sensitivity. ;
//
// NOTE: THIS IS MATCH BEGIN CASE WITHOUT WILD CARD. The non-wild case
// for bMatchEntire (DO_MATCH) does NOT come through this section of
// code. Rather, flmCurDoEQ is called instead of this routine in that
// case.
if (pLhs->eType == FLM_TEXT_VAL && pRhs->eType == FLM_TEXT_VAL)
{
// Always true if there is a wild card.
uiTrueFalse = flmTextMatch( pLhs->val.pucBuf, pLhs->uiBufLen,
pRhs->val.pucBuf, pRhs->uiBufLen, uiFlags,
bLeadingWildCard, bTrailingWildCard, uiLang);
}
else
{
uiTrueFalse = FLM_FALSE;
}
Exit:
return (uiTrueFalse);
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT flmCurDoContainsOp(
FQATOM * pLhs,
FQATOM * pRhs,
FLMUINT uiLang)
{
FLMBYTE * pResult = NULL;
FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags;
FLMUINT uiTrueFalse = 0;
// Verify operands -- both should be buffered types
if (!IS_BUF_TYPE( pLhs->eType) || !IS_BUF_TYPE( pRhs->eType))
{
goto Exit;
}
// If one of the operands is binary, simply do a byte comparison of the
// two values without regard to case or wildcards.
if ((pLhs->eType == FLM_BINARY_VAL) || (pRhs->eType == FLM_BINARY_VAL))
{
uiTrueFalse = FLM_FALSE;
for (pResult = pLhs->val.pucBuf;
(FLMUINT) (pResult - pLhs->val.pucBuf) < pLhs->uiBufLen;
pResult++)
{
if ((*pResult == pRhs->val.pucBuf[0]) &&
(f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf,
pRhs->uiBufLen) == 0))
{
uiTrueFalse = FLM_TRUE;
goto Exit;
}
}
goto Exit;
}
uiTrueFalse = flmTextMatch( pLhs->val.pucBuf, pLhs->uiBufLen,
pRhs->val.pucBuf, pRhs->uiBufLen, uiFlags,
TRUE, TRUE, uiLang);
Exit:
return (uiTrueFalse);
}
/****************************************************************************
Desc:
****************************************************************************/
FLMINT flmCurDoRelationalOp(
FQATOM * pLhs,
FQATOM * pRhs,
FLMUINT uiLang)
{
FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags;
FLMINT iCompVal = 0;
switch (pLhs->eType)
{
case FLM_TEXT_VAL:
{
flmAssert( pRhs->eType == FLM_TEXT_VAL);
iCompVal = flmTextCompare( pLhs->val.pucBuf, pLhs->uiBufLen,
pRhs->val.pucBuf, pRhs->uiBufLen, uiFlags,
uiLang);
break;
}
case FLM_UINT32_VAL:
{
switch (pRhs->eType)
{
case FLM_UINT32_VAL:
{
iCompVal = FQ_COMPARE( pLhs->val.ui32Val, pRhs->val.ui32Val);
break;
}
case FLM_UINT64_VAL:
{
iCompVal = FQ_COMPARE( (FLMUINT64)(pLhs->val.ui32Val),
pRhs->val.ui64Val);
break;
}
case FLM_INT32_VAL:
{
if (pRhs->val.i32Val < 0)
{
iCompVal = 1;
}
else
{
iCompVal = FQ_COMPARE( pLhs->val.ui32Val,
(FLMUINT32)pRhs->val.i32Val);
}
break;
}
case FLM_INT64_VAL:
{
if (pRhs->val.i64Val < 0)
{
iCompVal = 1;
}
else
{
iCompVal = FQ_COMPARE( (FLMINT64)(pLhs->val.ui32Val),
pRhs->val.i64Val);
}
break;
}
default:
{
flmAssert( 0);
break;
}
}
break;
}
case FLM_UINT64_VAL:
{
switch (pRhs->eType)
{
case FLM_UINT32_VAL:
{
iCompVal = FQ_COMPARE( pLhs->val.ui64Val, (FLMUINT64)pRhs->val.ui32Val);
break;
}
case FLM_UINT64_VAL:
{
iCompVal = FQ_COMPARE( pLhs->val.ui64Val, pRhs->val.ui64Val);
break;
}
case FLM_INT32_VAL:
{
if (pRhs->val.i32Val < 0)
{
iCompVal = 1;
}
else
{
iCompVal = FQ_COMPARE( pLhs->val.ui64Val,
(FLMUINT64)(pRhs->val.i32Val));
}
break;
}
case FLM_INT64_VAL:
{
if (pRhs->val.i64Val < 0)
{
iCompVal = 1;
}
else
{
iCompVal = FQ_COMPARE( pLhs->val.ui64Val,
(FLMUINT64)(pRhs->val.i64Val));
}
break;
}
default:
{
flmAssert( 0);
break;
}
}
break;
}
case FLM_INT32_VAL:
{
switch (pRhs->eType)
{
case FLM_INT32_VAL:
{
iCompVal = FQ_COMPARE( pLhs->val.i32Val, pRhs->val.i32Val);
break;
}
case FLM_INT64_VAL:
{
iCompVal = FQ_COMPARE( (FLMINT64)(pLhs->val.i32Val), pRhs->val.i64Val);
break;
}
case FLM_UINT32_VAL:
{
if (pLhs->val.i32Val < 0)
{
iCompVal = -1;
}
else
{
iCompVal = FQ_COMPARE( (FLMUINT) pLhs->val.i32Val,
pRhs->val.ui32Val);
}
break;
}
case FLM_UINT64_VAL:
{
if (pLhs->val.i32Val < 0)
{
iCompVal = -1;
}
else
{
iCompVal = FQ_COMPARE( (FLMUINT64)(pLhs->val.i32Val),
pRhs->val.ui64Val);
}
break;
}
default:
{
flmAssert( 0);
break;
}
}
break;
}
case FLM_INT64_VAL:
{
switch (pRhs->eType)
{
case FLM_INT32_VAL:
{
iCompVal = FQ_COMPARE( pLhs->val.i64Val, (FLMINT64)(pRhs->val.i32Val));
break;
}
case FLM_INT64_VAL:
{
iCompVal = FQ_COMPARE( pLhs->val.i64Val, pRhs->val.i64Val);
break;
}
case FLM_UINT32_VAL:
{
if (pLhs->val.i64Val < 0)
{
iCompVal = -1;
}
else
{
iCompVal = FQ_COMPARE( pLhs->val.i64Val,
(FLMINT64)(pRhs->val.ui32Val));
}
break;
}
case FLM_UINT64_VAL:
{
if (pLhs->val.i64Val < 0)
{
iCompVal = -1;
}
else
{
iCompVal = FQ_COMPARE( (FLMUINT64)(pLhs->val.i64Val),
pRhs->val.ui64Val);
}
break;
}
default:
{
flmAssert( 0);
break;
}
}
break;
}
case FLM_REC_PTR_VAL:
{
if (pRhs->eType == FLM_REC_PTR_VAL ||
pRhs->eType == FLM_UINT32_VAL)
{
iCompVal = FQ_COMPARE( pLhs->val.ui32Val, pRhs->val.ui32Val);
}
else if (pRhs->eType == FLM_UINT64_VAL)
{
iCompVal = FQ_COMPARE( (FLMUINT64)(pLhs->val.ui32Val), pRhs->val.ui64Val);
}
else
{
flmAssert( 0);
}
break;
}
case FLM_BINARY_VAL:
{
flmAssert( (pRhs->eType == FLM_BINARY_VAL) ||
(pRhs->eType == FLM_TEXT_VAL));
if ((iCompVal = f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf,
((pLhs->uiBufLen > pRhs->uiBufLen)
? pRhs->uiBufLen
: pLhs->uiBufLen))) == 0)
{
if (pLhs->uiBufLen < pRhs->uiBufLen)
{
iCompVal = -1;
}
else if (pLhs->uiBufLen > pRhs->uiBufLen)
{
iCompVal = 1;
}
}
break;
}
default:
{
flmAssert( 0);
break;
}
}
return (iCompVal);
}