git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@509 0109f412-320b-0410-ab79-c3e0c5ffbbe6
3650 lines
76 KiB
C++
3650 lines
76 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Query evaluation
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1994-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: fqeval.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
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);
|
|
|
|
FSTATIC RCODE OpSyntaxError(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUBitAND(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUBitOR(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUBitXOR(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUSMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSSMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSUMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpURMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRUMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSRMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRSMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRRMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUSDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSSDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSUDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpURDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRUDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSRDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRSDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRRDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUSMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSSMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSUMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUSPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSSPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSUPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpURPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRUPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSRPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRSPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRRPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUUMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpUSMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSSMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSUMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpURMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRUMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpSRMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRSMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
FSTATIC RCODE OpRRMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult);
|
|
|
|
#define IS_EXPORT_PTR(e) \
|
|
((e) == FLM_TEXT_VAL || (e) == FLM_BINARY_VAL)
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FQ_OPERATION * FQ_DoOperation[((LAST_ARITH_OP - FIRST_ARITH_OP) + 1) * 9] =
|
|
{
|
|
// BITAND
|
|
|
|
OpUUBitAND,
|
|
OpUUBitAND,
|
|
OpSyntaxError,
|
|
OpUUBitAND,
|
|
OpUUBitAND,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
|
|
// BITOR
|
|
|
|
OpUUBitOR,
|
|
OpUUBitOR,
|
|
OpSyntaxError,
|
|
OpUUBitOR,
|
|
OpUUBitOR,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
|
|
// BITXOR
|
|
|
|
OpUUBitXOR,
|
|
OpUUBitXOR,
|
|
OpSyntaxError,
|
|
OpUUBitXOR,
|
|
OpUUBitXOR,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
|
|
// MULT
|
|
|
|
OpUUMult,
|
|
OpUSMult,
|
|
OpURMult,
|
|
OpSUMult,
|
|
OpSSMult,
|
|
OpSRMult,
|
|
OpRUMult,
|
|
OpRSMult,
|
|
OpRRMult,
|
|
|
|
// DIV
|
|
|
|
OpUUDiv,
|
|
OpUSDiv,
|
|
OpURDiv,
|
|
OpSUDiv,
|
|
OpSSDiv,
|
|
OpSRDiv,
|
|
OpRUDiv,
|
|
OpRSDiv,
|
|
OpRRDiv,
|
|
|
|
// MOD
|
|
|
|
OpUUMod,
|
|
OpUSMod,
|
|
OpSyntaxError,
|
|
OpSUMod,
|
|
OpSSMod,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
OpSyntaxError,
|
|
|
|
// PLUS
|
|
|
|
OpUUPlus,
|
|
OpUSPlus,
|
|
OpURPlus,
|
|
OpSUPlus,
|
|
OpSSPlus,
|
|
OpSRPlus,
|
|
OpRUPlus,
|
|
OpRSPlus,
|
|
OpRRPlus,
|
|
|
|
// MINUS
|
|
|
|
OpUUMinus,
|
|
OpUSMinus,
|
|
OpURMinus,
|
|
OpSUMinus,
|
|
OpSSMinus,
|
|
OpSRMinus,
|
|
OpRUMinus,
|
|
OpRSMinus,
|
|
OpRRMinus
|
|
};
|
|
|
|
/****************************************************************************
|
|
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.iVal)
|
|
{
|
|
uiTrueFalse |= FLM_TRUE;
|
|
}
|
|
else
|
|
{
|
|
uiTrueFalse |= FLM_FALSE;
|
|
}
|
|
break;
|
|
case FLM_UINT32_VAL:
|
|
if (pTmpQAtom->val.uiVal)
|
|
{
|
|
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:
|
|
{
|
|
if (!pField || pRecord->getDataLength( pField) == 0)
|
|
{
|
|
// Default value
|
|
|
|
pResult->val.iVal = 0;
|
|
}
|
|
else if (uiType == FLM_NUMBER_TYPE || uiType == FLM_TEXT_TYPE)
|
|
{
|
|
if (RC_BAD( rc = pRecord->getINT( pField, &pResult->val.iVal)))
|
|
{
|
|
|
|
// Try to get the number as an unsigned value. For purposes
|
|
// of evaluation, the 32-bit value will still be treated as
|
|
// signed. In effect, the large positive value is wrapped and
|
|
// becomes a negative value.
|
|
|
|
if (rc == FERR_CONV_NUM_OVERFLOW)
|
|
{
|
|
rc = pRecord->getUINT( pField, &pResult->val.uiVal);
|
|
eFldType = FLM_UINT32_VAL;
|
|
}
|
|
}
|
|
}
|
|
else if (uiType == FLM_CONTEXT_TYPE)
|
|
{
|
|
rc = pRecord->getUINT( pField, &pResult->val.uiVal);
|
|
eFldType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( FERR_CONV_BAD_SRC_TYPE);
|
|
}
|
|
|
|
if (RC_OK( rc))
|
|
{
|
|
pResult->eType = eFldType;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FLM_UINT32_VAL:
|
|
case FLM_REC_PTR_VAL:
|
|
{
|
|
if (!pField || pRecord->getDataLength( pField) == 0)
|
|
{
|
|
// Default value
|
|
|
|
pResult->val.uiVal = 0;
|
|
}
|
|
else if (uiType == FLM_NUMBER_TYPE || uiType == FLM_TEXT_TYPE)
|
|
{
|
|
if (RC_BAD( rc = pRecord->getUINT( pField, &pResult->val.uiVal)))
|
|
{
|
|
|
|
// Try to get the number as a signed value. For purposes of
|
|
// evaluation, the 32-bit value will still be treated as
|
|
// unsigned. In effect, the negative value is wrapped and
|
|
// becomes a large positive value.
|
|
|
|
if (rc == FERR_CONV_NUM_UNDERFLOW)
|
|
{
|
|
rc = pRecord->getINT( pField, &pResult->val.iVal);
|
|
eFldType = FLM_INT32_VAL;
|
|
}
|
|
}
|
|
}
|
|
else if (uiType == FLM_CONTEXT_TYPE)
|
|
{
|
|
rc = pRecord->getUINT( pField, &(pResult->val.uiVal));
|
|
}
|
|
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->getUINT( pField,
|
|
&pResult->val.uiVal)))
|
|
{
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else if (RC_OK( rc = pRecord->getINT( pField,
|
|
&pResult->val.iVal)))
|
|
{
|
|
pResult->eType = FLM_INT32_VAL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FLM_CONTEXT_TYPE:
|
|
{
|
|
if (RC_OK( rc = pRecord->getUINT( pField,
|
|
&(pResult->val.uiVal))))
|
|
{
|
|
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;
|
|
void * pvLastLevelOneField = NULL;
|
|
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.uiVal = 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 ((pvLastLevelOneField =
|
|
pRecord->findLevelOneField( uiLevelOneFieldId, FALSE)) == NULL)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiCurrFieldPath [0] = puiPToCPath [0];
|
|
pvField = pvLastLevelOneField;
|
|
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)
|
|
{
|
|
pvLastLevelOneField = pvField = pRecord->nextLevelOneField(
|
|
pvLastLevelOneField);
|
|
}
|
|
|
|
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.uiVal = 0;
|
|
|
|
pRhs->pNext = NULL;
|
|
pRhs->pFieldRec = NULL;
|
|
pRhs->eType = NO_TYPE;
|
|
pRhs->uiBufLen = 0;
|
|
pRhs->val.uiVal = 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
|
|
{
|
|
int opPos = (eOp - FIRST_ARITH_OP) * 9;
|
|
QTYPES lhType = (QTYPES) (pLhs->eType - FLM_UINT32_VAL);
|
|
QTYPES rhType = (QTYPES) (pRhs->eType - FLM_UINT32_VAL);
|
|
|
|
if (lhType > 2 || rhType > 2)
|
|
{
|
|
rc = RC_SET( FERR_CURSOR_SYNTAX);
|
|
goto Exit;
|
|
}
|
|
|
|
opPos += (lhType * 3) + rhType;
|
|
|
|
// Call through a table the operation handling routine.
|
|
|
|
rc = (FQ_DoOperation[opPos]) (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.uiVal, pRhs->val.uiVal) == 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 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.uiVal = 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 OpSyntaxError(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
F_UNREFERENCED_PARM( pLhs);
|
|
F_UNREFERENCED_PARM( pRhs);
|
|
F_UNREFERENCED_PARM( pResult);
|
|
|
|
return (RC_SET( FERR_CURSOR_SYNTAX));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUBitAND(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal & pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUBitOR(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal | pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUBitXOR(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal ^ pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal * pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUSMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.iVal = (FLMINT) pLhs->val.uiVal * pRhs->val.iVal;
|
|
pResult->eType = FLM_INT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSSMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal * pRhs->val.iVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSUMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal * (FLMINT) pRhs->val.uiVal;
|
|
pResult->eType = FLM_INT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpURMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRUMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSRMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRSMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRRMult(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.uiVal)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal / pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
// Divide by ZERO case.
|
|
|
|
pResult->val.uiVal = 0;
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUSDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.iVal)
|
|
{
|
|
pResult->val.iVal = (FLMINT) pLhs->val.uiVal / pRhs->val.iVal;
|
|
pResult->eType = FLM_INT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
// Divide by ZERO case.
|
|
|
|
pResult->val.uiVal = 0;
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSSDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.iVal)
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal / pRhs->val.iVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // divide by ZERO case
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSUDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.uiVal)
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal / (FLMINT) pRhs->val.uiVal;
|
|
pResult->eType = FLM_INT32_VAL;
|
|
}
|
|
else // Divide by ZERO case - let's try not to crash.
|
|
{
|
|
pResult->val.uiVal = 0;
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpURDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRUDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSRDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRSDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRRDiv(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.uiVal != 0)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal % pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUSMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.iVal != 0)
|
|
{
|
|
pResult->val.iVal = (FLMINT) pLhs->val.uiVal / pRhs->val.iVal;
|
|
pResult->eType = FLM_INT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSSMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.iVal != 0)
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal % pRhs->val.iVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
// MOD by ZERO case
|
|
|
|
pResult->val.uiVal = 0;
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSUMod(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.uiVal != 0)
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal % ((FLMINT) pRhs->val.uiVal);
|
|
pResult->eType = FLM_INT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
// Divide by ZERO case.
|
|
|
|
pResult->val.uiVal = 0;
|
|
pResult->eType = FLM_UNKNOWN;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal + pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUSPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if ((pRhs->val.iVal >= 0) || (pLhs->val.uiVal > MAX_SIGNED_VAL))
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal + (FLMUINT) pRhs->val.iVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = (FLMINT) pLhs->val.uiVal + pRhs->val.iVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSSPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal + pRhs->val.iVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSUPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if ((pLhs->val.iVal >= 0) || (pRhs->val.uiVal > MAX_SIGNED_VAL))
|
|
{
|
|
pResult->val.uiVal = (FLMUINT) pLhs->val.iVal + pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal + (FLMINT) pRhs->val.uiVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpURPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRUPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSRPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRSPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRRPlus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUUMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pLhs->val.uiVal >= pRhs->val.uiVal)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal - pRhs->val.uiVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = (FLMINT) (pLhs->val.uiVal - pRhs->val.uiVal);
|
|
pResult->eType = FLM_INT32_VAL;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpUSMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
|
|
if (pRhs->val.iVal < 0)
|
|
{
|
|
pResult->val.uiVal = pLhs->val.uiVal - pRhs->val.iVal;
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = (FLMINT) pLhs->val.uiVal - pRhs->val.iVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSSMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if ((pLhs->val.iVal > 0) && (pRhs->val.iVal < 0))
|
|
{
|
|
pResult->val.uiVal = (FLMUINT) (pLhs->val.iVal - pRhs->val.iVal);
|
|
pResult->eType = FLM_UINT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal - pRhs->val.iVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSUMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
if (pRhs->val.uiVal > MAX_SIGNED_VAL)
|
|
{
|
|
pResult->val.iVal = (pLhs->val.iVal - MAX_SIGNED_VAL) -
|
|
(FLMINT) (pRhs->val.uiVal - MAX_SIGNED_VAL);
|
|
pResult->eType = FLM_INT32_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = pLhs->val.iVal - (FLMINT) pRhs->val.uiVal;
|
|
pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL;
|
|
}
|
|
|
|
return (FERR_OK);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpURMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRUMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpSRMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRSMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC RCODE OpRRMinus(
|
|
FQATOM * pLhs,
|
|
FQATOM * pRhs,
|
|
FQATOM * pResult)
|
|
{
|
|
return (OpSyntaxError( pLhs, pRhs, pResult));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
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 (pTmpQAtom->val.uiVal >= MAX_SIGNED_VAL)
|
|
{
|
|
pTmpQAtom->eType = NO_TYPE;
|
|
}
|
|
else
|
|
{
|
|
pTmpQAtom->val.iVal = -((FLMINT) (pTmpQAtom->val.uiVal));
|
|
pTmpQAtom->eType = FLM_INT32_VAL;
|
|
}
|
|
}
|
|
else if (IS_SIGNED( pTmpQAtom->eType))
|
|
{
|
|
pTmpQAtom->val.iVal *= -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.uiVal, pRhs->val.uiVal);
|
|
break;
|
|
}
|
|
|
|
case FLM_INT32_VAL:
|
|
{
|
|
if (pRhs->val.iVal < 0)
|
|
{
|
|
iCompVal = 1;
|
|
}
|
|
else
|
|
{
|
|
iCompVal = FQ_COMPARE( pLhs->val.uiVal,
|
|
(FLMUINT) pRhs->val.iVal);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
flmAssert( 0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FLM_INT32_VAL:
|
|
{
|
|
switch (pRhs->eType)
|
|
{
|
|
case FLM_INT32_VAL:
|
|
{
|
|
iCompVal = FQ_COMPARE( pLhs->val.iVal, pRhs->val.iVal);
|
|
break;
|
|
}
|
|
|
|
case FLM_UINT32_VAL:
|
|
{
|
|
if (pLhs->val.iVal < 0)
|
|
{
|
|
iCompVal = -1;
|
|
}
|
|
else
|
|
{
|
|
iCompVal = FQ_COMPARE( (FLMUINT) pLhs->val.iVal,
|
|
pRhs->val.uiVal);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
flmAssert( 0);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FLM_REC_PTR_VAL:
|
|
{
|
|
flmAssert( pRhs->eType == FLM_REC_PTR_VAL ||
|
|
pRhs->eType == FLM_UINT32_VAL);
|
|
|
|
iCompVal = FQ_COMPARE( pLhs->val.uiVal, pRhs->val.uiVal);
|
|
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);
|
|
}
|