git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
3882 lines
82 KiB
C++
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);
|
|
}
|