git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@729 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2243 lines
54 KiB
C++
2243 lines
54 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Parse SQL
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 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$
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
// Local function prototypes
|
|
|
|
FSTATIC RCODE sqlCompareText(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
FLMUINT uiCompareRules,
|
|
FLMBOOL bOpIsMatch,
|
|
FLMUINT uiLanguage,
|
|
FLMINT * piResult);
|
|
|
|
FSTATIC RCODE sqlApproxCompare(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
FLMINT * piResult);
|
|
|
|
FSTATIC RCODE sqlCompareBinary(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
FLMINT * piResult);
|
|
|
|
FSTATIC void sqlArithOpUUBitAND(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUUBitOR(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUUBitXOR(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUUMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUSMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSSMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSUMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUUDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUSDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSSDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSUDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUUMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUSMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSSMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSUMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUUPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUSPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSSPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSUPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUUMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpUSMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSSMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC void sqlArithOpSUMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
FSTATIC RCODE sqlCompareOperands(
|
|
FLMUINT uiLanguage,
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
eSQLQueryOperators eOperator,
|
|
FLMUINT uiCompareRules,
|
|
FLMBOOL bNotted,
|
|
SQLBoolType * peBool);
|
|
|
|
FSTATIC RCODE sqlGetColumnValue(
|
|
F_Db * pDb,
|
|
F_Row * pRow,
|
|
FLMUINT uiTableNum,
|
|
FLMUINT uiColumnNum,
|
|
F_Pool * pPool,
|
|
SQL_VALUE * pSqlValue);
|
|
|
|
FSTATIC RCODE sqlEvalOperator(
|
|
FLMUINT uiLanguage,
|
|
SQL_NODE * pQNode);
|
|
|
|
typedef void SQL_ARITH_OP(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult);
|
|
|
|
SQL_ARITH_OP * SQL_ArithOpTable[
|
|
((SQL_LAST_ARITH_OP - SQL_FIRST_ARITH_OP) + 1) * 4 ] =
|
|
{
|
|
/* U = Unsigned S = Signed
|
|
U + U U + S
|
|
S + U S + S */
|
|
/* BITAND */ sqlArithOpUUBitAND, sqlArithOpUUBitAND,
|
|
sqlArithOpUUBitAND, sqlArithOpUUBitAND,
|
|
/* BITOR */ sqlArithOpUUBitOR, sqlArithOpUUBitOR,
|
|
sqlArithOpUUBitOR, sqlArithOpUUBitOR,
|
|
/* BITXOR */ sqlArithOpUUBitXOR, sqlArithOpUUBitXOR,
|
|
sqlArithOpUUBitXOR, sqlArithOpUUBitXOR,
|
|
/* MULT */ sqlArithOpUUMult, sqlArithOpUSMult,
|
|
sqlArithOpSUMult, sqlArithOpSSMult,
|
|
/* DIV */ sqlArithOpUUDiv, sqlArithOpUSDiv,
|
|
sqlArithOpSUDiv, sqlArithOpSSDiv,
|
|
/* MOD */ sqlArithOpUUMod, sqlArithOpUSMod,
|
|
sqlArithOpSUMod, sqlArithOpSSMod,
|
|
/* PLUS */ sqlArithOpUUPlus, sqlArithOpUSPlus,
|
|
sqlArithOpSUPlus, sqlArithOpSSPlus,
|
|
/* MINUS */ sqlArithOpUUMinus, sqlArithOpUSMinus,
|
|
sqlArithOpSUMinus, sqlArithOpSSMinus
|
|
};
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Desc: Compare two entire strings.
|
|
//-------------------------------------------------------------------------
|
|
FSTATIC RCODE sqlCompareText(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
FLMUINT uiCompareRules,
|
|
FLMBOOL bOpIsMatch,
|
|
FLMUINT uiLanguage,
|
|
FLMINT * piResult)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
F_BufferIStream bufferLStream;
|
|
IF_PosIStream * pLStream;
|
|
F_BufferIStream bufferRStream;
|
|
IF_PosIStream * pRStream;
|
|
|
|
// Types must be text
|
|
|
|
if (pLValue->eValType != SQL_UTF8_VAL || pRValue->eValType != SQL_UTF8_VAL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_Q_COMPARE_OPERAND_TYPE_MISMATCH);
|
|
goto Exit;
|
|
}
|
|
|
|
// Open the streams
|
|
|
|
if (RC_BAD( rc = bufferLStream.openStream(
|
|
(const char *)pLValue->val.str.pszStr, pLValue->val.str.uiByteLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pLStream = &bufferLStream;
|
|
|
|
if( RC_BAD( rc = bufferRStream.openStream(
|
|
(const char *)pRValue->val.str.pszStr, pRValue->val.str.uiByteLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pRStream = &bufferRStream;
|
|
|
|
if( RC_BAD( rc = f_compareUTF8Streams(
|
|
pLStream,
|
|
(bOpIsMatch && (pLValue->uiFlags & SQL_VAL_IS_CONSTANT)) ? TRUE : FALSE,
|
|
pRStream,
|
|
(bOpIsMatch && (pRValue->uiFlags & SQL_VAL_IS_CONSTANT)) ? TRUE : FALSE,
|
|
uiCompareRules, uiLanguage, piResult)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Desc: Performs approximate compare on two strings.
|
|
//-------------------------------------------------------------------------
|
|
FSTATIC RCODE sqlApproxCompare(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
FLMINT * piResult)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiLMeta;
|
|
FLMUINT uiRMeta;
|
|
FLMUINT64 ui64StartPos;
|
|
F_BufferIStream bufferLStream;
|
|
IF_PosIStream * pLStream;
|
|
F_BufferIStream bufferRStream;
|
|
IF_PosIStream * pRStream;
|
|
|
|
// Types must be text
|
|
|
|
if (pLValue->eValType != SQL_UTF8_VAL ||
|
|
pRValue->eValType != SQL_UTF8_VAL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// Open the streams
|
|
|
|
if (RC_BAD( rc = bufferLStream.openStream(
|
|
(const char *)pLValue->val.str.pszStr, pLValue->val.str.uiByteLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pLStream = &bufferLStream;
|
|
|
|
if( RC_BAD( rc = bufferRStream.openStream(
|
|
(const char *)pRValue->val.str.pszStr, pRValue->val.str.uiByteLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pRStream = &bufferRStream;
|
|
|
|
if ((pLValue->uiFlags & SQL_VAL_IS_CONSTANT) ||
|
|
!(pRValue->uiFlags & SQL_VAL_IS_CONSTANT))
|
|
{
|
|
for( ;;)
|
|
{
|
|
if (RC_BAD( rc = f_getNextMetaphone( pLStream, &uiLMeta)))
|
|
{
|
|
if( rc == NE_FLM_EOF_HIT)
|
|
{
|
|
*piResult = 0;
|
|
rc = NE_SFLM_OK;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
ui64StartPos = pRStream->getCurrPosition();
|
|
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = f_getNextMetaphone( pRStream, &uiRMeta)))
|
|
{
|
|
if( rc == NE_FLM_EOF_HIT)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
*piResult = -1;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiLMeta == uiRMeta)
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if( RC_BAD( rc = pRStream->positionTo( ui64StartPos)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = f_getNextMetaphone( pRStream, &uiRMeta)))
|
|
{
|
|
if( rc == NE_FLM_EOF_HIT)
|
|
{
|
|
*piResult = 0;
|
|
rc = NE_SFLM_OK;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
ui64StartPos = pLStream->getCurrPosition();
|
|
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = f_getNextMetaphone( pLStream, &uiLMeta)))
|
|
{
|
|
if( rc == NE_FLM_EOF_HIT)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
*piResult = 1;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiLMeta == uiRMeta)
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if( RC_BAD( rc = pLStream->positionTo( ui64StartPos)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Desc: Performs binary comparison on two streams - may be text or binary,
|
|
// it really doesn't matter. Returns SQL_TRUE or SQL_FALSE.
|
|
//-------------------------------------------------------------------------
|
|
FSTATIC RCODE sqlCompareBinary(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
FLMINT * piResult)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
F_BufferIStream bufferLStream;
|
|
IF_PosIStream * pLStream;
|
|
F_BufferIStream bufferRStream;
|
|
IF_PosIStream * pRStream;
|
|
FLMBYTE ucLByte;
|
|
FLMBYTE ucRByte;
|
|
FLMUINT uiOffset = 0;
|
|
FLMBOOL bLEmpty = FALSE;
|
|
|
|
*piResult = 0;
|
|
|
|
// Types must be binary
|
|
|
|
if (pLValue->eValType != SQL_BINARY_VAL ||
|
|
pRValue->eValType != SQL_BINARY_VAL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_Q_COMPARE_OPERAND_TYPE_MISMATCH);
|
|
goto Exit;
|
|
}
|
|
|
|
// Open the streams
|
|
|
|
if (RC_BAD( rc = bufferLStream.openStream(
|
|
(const char *)pLValue->val.str.pszStr, pLValue->val.str.uiByteLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pLStream = &bufferLStream;
|
|
|
|
if( RC_BAD( rc = bufferRStream.openStream(
|
|
(const char *)pRValue->val.str.pszStr, pRValue->val.str.uiByteLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pRStream = &bufferRStream;
|
|
|
|
for (;;)
|
|
{
|
|
if (RC_BAD( rc = flmReadStorageAsBinary(
|
|
pLStream, &ucLByte, 1, uiOffset, NULL)))
|
|
{
|
|
if (rc == NE_SFLM_EOF_HIT)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
bLEmpty = TRUE;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (RC_BAD( rc = flmReadStorageAsBinary(
|
|
pRStream, &ucRByte, 1, uiOffset, NULL)))
|
|
{
|
|
if (rc == NE_SFLM_EOF_HIT)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
if( bLEmpty)
|
|
{
|
|
*piResult = 0;
|
|
}
|
|
else
|
|
{
|
|
*piResult = 1;
|
|
}
|
|
}
|
|
goto Exit;
|
|
}
|
|
else if( bLEmpty)
|
|
{
|
|
*piResult = -1;
|
|
goto Exit;
|
|
}
|
|
|
|
if( ucLByte != ucRByte)
|
|
{
|
|
*piResult = ucLByte < ucRByte ? -1 : 1;
|
|
goto Exit;
|
|
}
|
|
|
|
uiOffset++;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Desc: Compare two values. This routine assumes that pValue1 and pValue2
|
|
// are non-null.
|
|
//-------------------------------------------------------------------------
|
|
RCODE sqlCompare(
|
|
SQL_VALUE * pValue1,
|
|
SQL_VALUE * pValue2,
|
|
FLMUINT uiCompareRules,
|
|
FLMUINT uiLanguage,
|
|
FLMINT * piCmp)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
// We have already called sqlCanCompare, so no need to do it here
|
|
|
|
switch (pValue1->eValType)
|
|
{
|
|
case SQL_BOOL_VAL:
|
|
*piCmp = pValue1->val.eBool > pValue2->val.eBool
|
|
? 1
|
|
: pValue1->val.eBool < pValue2->val.eBool
|
|
? -1
|
|
: 0;
|
|
break;
|
|
case SQL_UINT_VAL:
|
|
switch (pValue2->eValType)
|
|
{
|
|
case SQL_UINT_VAL:
|
|
*piCmp = pValue1->val.uiVal > pValue2->val.uiVal
|
|
? 1
|
|
: pValue1->val.uiVal < pValue2->val.uiVal
|
|
? -1
|
|
: 0;
|
|
break;
|
|
case SQL_UINT64_VAL:
|
|
*piCmp = (FLMUINT64)pValue1->val.uiVal > pValue2->val.ui64Val
|
|
? 1
|
|
: (FLMUINT64)pValue1->val.uiVal < pValue2->val.ui64Val
|
|
? -1
|
|
: 0;
|
|
break;
|
|
case SQL_INT_VAL:
|
|
*piCmp = pValue2->val.iVal < 0 ||
|
|
pValue1->val.uiVal > (FLMUINT)pValue2->val.iVal
|
|
? 1
|
|
: pValue1->val.uiVal < (FLMUINT)pValue2->val.iVal
|
|
? -1
|
|
: 0;
|
|
break;
|
|
case SQL_INT64_VAL:
|
|
*piCmp = pValue2->val.i64Val < 0 ||
|
|
(FLMUINT64)pValue1->val.uiVal >
|
|
(FLMUINT64)pValue2->val.i64Val
|
|
? 1
|
|
: (FLMUINT64)pValue1->val.uiVal <
|
|
(FLMUINT64)pValue2->val.i64Val
|
|
? -1
|
|
: 0;
|
|
break;
|
|
default:
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_Q_COMPARE_OPERAND_TYPE_MISMATCH);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
case SQL_UINT64_VAL:
|
|
switch (pValue2->eValType)
|
|
{
|
|
case SQL_UINT_VAL:
|
|
*piCmp = pValue1->val.ui64Val > (FLMUINT64)pValue2->val.uiVal
|
|
? 1
|
|
: pValue1->val.ui64Val < (FLMUINT64)pValue2->val.uiVal
|
|
? -1
|
|
: 0;
|
|
break;
|
|
case SQL_UINT64_VAL:
|
|
*piCmp = pValue1->val.ui64Val > pValue2->val.ui64Val
|
|
? 1
|
|
: pValue1->val.ui64Val < pValue2->val.ui64Val
|
|
? -1
|
|
: 0;
|
|
break;
|
|
case SQL_INT_VAL:
|
|
*piCmp = pValue2->val.iVal < 0 ||
|
|
pValue1->val.ui64Val > (FLMUINT64)pValue2->val.iVal
|
|
? 1
|
|
: pValue1->val.ui64Val < (FLMUINT64)pValue2->val.iVal
|
|
? -1
|
|
: 0;
|
|
break;
|
|
case SQL_INT64_VAL:
|
|
*piCmp = pValue2->val.i64Val < 0 ||
|
|
pValue1->val.ui64Val > (FLMUINT64)pValue2->val.i64Val
|
|
? 1
|
|
: pValue1->val.ui64Val < (FLMUINT64)pValue2->val.i64Val
|
|
? -1
|
|
: 0;
|
|
break;
|
|
default:
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_Q_COMPARE_OPERAND_TYPE_MISMATCH);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
case SQL_INT_VAL:
|
|
switch (pValue2->eValType)
|
|
{
|
|
case SQL_UINT_VAL:
|
|
*piCmp = pValue1->val.iVal < 0 ||
|
|
(FLMUINT)pValue1->val.iVal < pValue2->val.uiVal
|
|
? -1
|
|
: (FLMUINT)pValue1->val.iVal > pValue2->val.uiVal
|
|
? 1
|
|
: 0;
|
|
break;
|
|
case SQL_UINT64_VAL:
|
|
*piCmp = pValue1->val.iVal < 0 ||
|
|
(FLMUINT64)pValue1->val.iVal < pValue2->val.ui64Val
|
|
? -1
|
|
: (FLMUINT64)pValue1->val.iVal > pValue2->val.ui64Val
|
|
? 1
|
|
: 0;
|
|
break;
|
|
case SQL_INT_VAL:
|
|
*piCmp = pValue1->val.iVal < pValue2->val.iVal
|
|
? -1
|
|
: pValue1->val.iVal > pValue2->val.iVal
|
|
? 1
|
|
: 0;
|
|
break;
|
|
case SQL_INT64_VAL:
|
|
*piCmp = (FLMINT64)pValue1->val.iVal < pValue2->val.i64Val
|
|
? -1
|
|
: (FLMINT64)pValue1->val.iVal > pValue2->val.i64Val
|
|
? 1
|
|
: 0;
|
|
break;
|
|
default:
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_Q_COMPARE_OPERAND_TYPE_MISMATCH);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
case SQL_INT64_VAL:
|
|
switch (pValue2->eValType)
|
|
{
|
|
case SQL_UINT_VAL:
|
|
*piCmp = pValue1->val.i64Val < 0 ||
|
|
(FLMUINT64)pValue1->val.i64Val <
|
|
(FLMUINT64)pValue2->val.uiVal
|
|
? -1
|
|
: (FLMUINT64)pValue1->val.i64Val >
|
|
(FLMUINT64)pValue2->val.uiVal
|
|
? 1
|
|
: 0;
|
|
break;
|
|
case SQL_UINT64_VAL:
|
|
*piCmp = pValue1->val.i64Val < 0 ||
|
|
(FLMUINT64)pValue1->val.i64Val < pValue2->val.ui64Val
|
|
? -1
|
|
: (FLMUINT64)pValue1->val.i64Val > pValue2->val.ui64Val
|
|
? 1
|
|
: 0;
|
|
break;
|
|
case SQL_INT_VAL:
|
|
*piCmp = pValue1->val.i64Val < (FLMINT64)pValue2->val.iVal
|
|
? -1
|
|
: pValue1->val.i64Val > (FLMINT64)pValue2->val.iVal
|
|
? 1
|
|
: 0;
|
|
break;
|
|
case SQL_INT64_VAL:
|
|
*piCmp = pValue1->val.i64Val < pValue2->val.i64Val
|
|
? -1
|
|
: pValue1->val.i64Val > pValue2->val.i64Val
|
|
? 1
|
|
: 0;
|
|
break;
|
|
default:
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_Q_COMPARE_OPERAND_TYPE_MISMATCH);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
case SQL_BINARY_VAL:
|
|
if (RC_BAD( rc = sqlCompareBinary( pValue1, pValue2, piCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
break;
|
|
case SQL_UTF8_VAL:
|
|
if (RC_BAD( rc = sqlCompareText( pValue1, pValue2,
|
|
uiCompareRules, FALSE, uiLanguage, piCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Desc: Returns a 64-bit unsigned integer
|
|
//-------------------------------------------------------------------------
|
|
FINLINE FLMUINT64 sqlGetUInt64(
|
|
SQL_VALUE * pValue)
|
|
{
|
|
if (pValue->eValType == SQL_UINT_VAL)
|
|
{
|
|
return( (FLMUINT64)pValue->val.uiVal);
|
|
}
|
|
else if( pValue->eValType == SQL_UINT64_VAL)
|
|
{
|
|
return( pValue->val.ui64Val);
|
|
}
|
|
else if( pValue->eValType == SQL_INT64_VAL)
|
|
{
|
|
if( pValue->val.i64Val >= 0)
|
|
{
|
|
return( (FLMUINT64)pValue->val.i64Val);
|
|
}
|
|
}
|
|
else if( pValue->eValType == SQL_INT_VAL)
|
|
{
|
|
if( pValue->val.iVal >= 0)
|
|
{
|
|
return( (FLMUINT64)pValue->val.iVal);
|
|
}
|
|
}
|
|
|
|
flmAssert( 0);
|
|
return( 0);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Desc: Returns a 64-bit signed integer
|
|
//-------------------------------------------------------------------------
|
|
FINLINE FLMINT64 sqlGetInt64(
|
|
SQL_VALUE * pValue)
|
|
{
|
|
if (pValue->eValType == SQL_INT_VAL)
|
|
{
|
|
return( (FLMINT64)pValue->val.iVal);
|
|
}
|
|
else if( pValue->eValType == SQL_INT64_VAL)
|
|
{
|
|
return( pValue->val.i64Val);
|
|
}
|
|
else if( pValue->eValType == SQL_UINT_VAL)
|
|
{
|
|
return( (FLMINT64)pValue->val.uiVal);
|
|
}
|
|
else if( pValue->eValType == SQL_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 sqlArithOpUUBitAND(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal & pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.ui64Val =
|
|
sqlGetUInt64( pLValue) & sqlGetUInt64( pRValue);
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the bit or operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUUBitOR(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal | pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.ui64Val =
|
|
sqlGetUInt64( pLValue) | sqlGetUInt64( pRValue);
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the bit xor operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUUBitXOR(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal ^ pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.ui64Val =
|
|
sqlGetUInt64( pLValue) ^ sqlGetUInt64( pRValue);
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the multiply operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUUMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal * pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.ui64Val =
|
|
sqlGetUInt64( pLValue) * sqlGetUInt64( pRValue);
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the multiply operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUSMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.iVal = (FLMINT)pLValue->val.uiVal * pRValue->val.iVal;
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = (FLMINT64)
|
|
sqlGetUInt64( pLValue) * sqlGetInt64( pRValue);
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the multiply operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSSMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal * pRValue->val.iVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL
|
|
: SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = (FLMINT64)(sqlGetInt64( pLValue) *
|
|
sqlGetInt64( pRValue));
|
|
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL
|
|
: SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the multiply operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSUMult(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal *
|
|
(FLMINT)pRValue->val.uiVal;
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = (FLMINT64)
|
|
(sqlGetInt64( pLValue) * sqlGetUInt64( pRValue));
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the divide operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUUDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.uiVal)
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal / pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT64 ui64LValue = sqlGetUInt64( pLValue);
|
|
FLMUINT64 ui64RValue = sqlGetUInt64( pRValue);
|
|
|
|
if( ui64RValue)
|
|
{
|
|
pResult->val.ui64Val = ui64LValue / ui64RValue;
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the divide operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUSDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.iVal)
|
|
{
|
|
pResult->val.iVal = pLValue->val.uiVal / pRValue->val.iVal;
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT64 ui64LValue = sqlGetUInt64( pLValue);
|
|
FLMINT64 i64RValue = sqlGetInt64( pRValue);
|
|
|
|
if( i64RValue)
|
|
{
|
|
pResult->val.i64Val = ui64LValue / i64RValue;
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the divide operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSSDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.iVal)
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal / pRValue->val.iVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMINT64 i64LValue = sqlGetInt64( pLValue);
|
|
FLMINT64 i64RValue = sqlGetInt64( pRValue);
|
|
|
|
if( i64RValue)
|
|
{
|
|
pResult->val.i64Val = i64LValue / i64RValue;
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the divide operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSUDiv(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.uiVal)
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal / pRValue->val.uiVal;
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMINT64 i64LValue = sqlGetInt64( pLValue);
|
|
FLMUINT64 ui64RValue = sqlGetUInt64( pRValue);
|
|
|
|
if( ui64RValue)
|
|
{
|
|
pResult->val.i64Val = i64LValue / ui64RValue;
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // Divide by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the modulo operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUUMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.uiVal)
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal % pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT64 ui64LValue = sqlGetUInt64( pLValue);
|
|
FLMUINT64 ui64RValue = sqlGetUInt64( pRValue);
|
|
|
|
if( ui64RValue)
|
|
{
|
|
pResult->val.ui64Val = ui64LValue % ui64RValue;
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the modulo operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUSMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.iVal)
|
|
{
|
|
pResult->val.iVal = pLValue->val.uiVal % pRValue->val.iVal;
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT64 ui64LValue = sqlGetUInt64( pLValue);
|
|
FLMINT64 i64RValue = sqlGetInt64( pRValue);
|
|
|
|
if( i64RValue)
|
|
{
|
|
pResult->val.i64Val = ui64LValue % i64RValue;
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the modulo operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSSMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.iVal)
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal % pRValue->val.iVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMINT64 i64LValue = sqlGetInt64( pLValue);
|
|
FLMINT64 i64RValue = sqlGetInt64( pRValue);
|
|
|
|
if( i64RValue)
|
|
{
|
|
pResult->val.i64Val = i64LValue % i64RValue;
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs the modulo operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSUMod(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.uiVal)
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal % pRValue->val.uiVal;
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMINT64 i64LValue = sqlGetInt64( pLValue);
|
|
FLMUINT64 ui64RValue = sqlGetUInt64( pRValue);
|
|
|
|
if( ui64RValue)
|
|
{
|
|
pResult->val.i64Val = i64LValue % ui64RValue;
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.uiVal = 0; // MOD by ZERO case.
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs an addition operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUUPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal + pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.ui64Val =
|
|
sqlGetUInt64( pLValue) + sqlGetUInt64( pRValue);
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs an addition operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUSPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( (pRValue->val.iVal >= 0) ||
|
|
(pLValue->val.uiVal > gv_uiMaxSignedIntVal))
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal + (FLMUINT)pRValue->val.iVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = (FLMINT)pLValue->val.uiVal + pRValue->val.iVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT64 ui64LValue = sqlGetUInt64( pLValue);
|
|
FLMINT64 i64RValue = sqlGetInt64( pRValue);
|
|
|
|
if( (i64RValue >= 0) || (ui64LValue > gv_ui64MaxSignedIntVal))
|
|
{ pResult->val.ui64Val = ui64LValue + (FLMUINT64)i64RValue;
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = (FLMINT64)ui64LValue + i64RValue;
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs an addition operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSSPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal + pRValue->val.iVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val =
|
|
sqlGetInt64( pLValue) + sqlGetInt64( pRValue);
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs an addition operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSUPlus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( (pLValue->val.iVal >= 0) ||
|
|
(pRValue->val.uiVal > gv_uiMaxSignedIntVal))
|
|
{
|
|
pResult->val.uiVal = (FLMUINT)pLValue->val.iVal + pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal + (FLMINT)pRValue->val.uiVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMINT64 i64LValue = sqlGetInt64( pLValue);
|
|
FLMUINT64 ui64RValue = sqlGetUInt64( pRValue);
|
|
|
|
if( (i64LValue >= 0) || (ui64RValue > gv_ui64MaxSignedIntVal))
|
|
{
|
|
pResult->val.ui64Val = (FLMUINT64)i64LValue + ui64RValue;
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = i64LValue + (FLMINT64)ui64RValue;
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs a subtraction operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUUMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pLValue->val.uiVal >= pRValue->val.uiVal)
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal - pRValue->val.uiVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = (FLMINT)(pLValue->val.uiVal - pRValue->val.uiVal);
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT64 ui64LValue = sqlGetUInt64( pLValue);
|
|
FLMUINT64 ui64RValue = sqlGetUInt64( pRValue);
|
|
|
|
if( ui64LValue >= ui64RValue)
|
|
{
|
|
pResult->val.ui64Val = ui64LValue - ui64RValue;
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = (FLMINT64)(ui64LValue - ui64RValue);
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs a subtraction operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpUSMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.iVal < 0)
|
|
{
|
|
pResult->val.uiVal = pLValue->val.uiVal - pRValue->val.iVal;
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = (FLMINT)pLValue->val.uiVal - pRValue->val.iVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT64 ui64LValue = sqlGetUInt64( pLValue);
|
|
FLMINT64 i64RValue = sqlGetInt64( pRValue);
|
|
|
|
if( i64RValue < 0)
|
|
{
|
|
pResult->val.ui64Val = ui64LValue - i64RValue;
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = (FLMINT64)ui64LValue - i64RValue;
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs a subtraction operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSSMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if(( pLValue->val.iVal > 0) && ( pRValue->val.iVal < 0))
|
|
{
|
|
pResult->val.uiVal = (FLMUINT)(pLValue->val.iVal - pRValue->val.iVal);
|
|
pResult->eValType = SQL_UINT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal - pRValue->val.iVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMINT64 i64LValue = sqlGetInt64( pLValue);
|
|
FLMINT64 i64RValue = sqlGetInt64( pRValue);
|
|
|
|
if( (i64LValue > 0) && (i64RValue < 0))
|
|
{
|
|
pResult->val.ui64Val = (FLMUINT64)( i64LValue - i64RValue);
|
|
pResult->eValType = SQL_UINT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = i64LValue - i64RValue;
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Performs a subtraction operation
|
|
***************************************************************************/
|
|
FSTATIC void sqlArithOpSUMinus(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
if (isSQLValNativeNum( pLValue->eValType) &&
|
|
isSQLValNativeNum( pRValue->eValType))
|
|
{
|
|
if( pRValue->val.uiVal > gv_uiMaxSignedIntVal)
|
|
{
|
|
pResult->val.iVal = (pLValue->val.iVal - gv_uiMaxSignedIntVal) -
|
|
(FLMINT)(pRValue->val.uiVal - gv_uiMaxSignedIntVal);
|
|
pResult->eValType = SQL_INT_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.iVal = pLValue->val.iVal - (FLMINT)pRValue->val.uiVal;
|
|
pResult->eValType = (pResult->val.iVal < 0)
|
|
? SQL_INT_VAL : SQL_UINT_VAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMINT64 i64LValue = sqlGetInt64( pLValue);
|
|
FLMUINT64 ui64RValue = sqlGetUInt64( pRValue);
|
|
|
|
if( ui64RValue > gv_ui64MaxSignedIntVal)
|
|
{
|
|
pResult->val.i64Val = (i64LValue - gv_ui64MaxSignedIntVal) -
|
|
(FLMINT64)(ui64RValue - gv_ui64MaxSignedIntVal);
|
|
pResult->eValType = SQL_INT64_VAL;
|
|
}
|
|
else
|
|
{
|
|
pResult->val.i64Val = i64LValue - (FLMINT64)ui64RValue;
|
|
pResult->eValType = (pResult->val.i64Val < 0)
|
|
? SQL_INT64_VAL : SQL_UINT64_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Do a comparison operator.
|
|
***************************************************************************/
|
|
FSTATIC RCODE sqlCompareOperands(
|
|
FLMUINT uiLanguage,
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
eSQLQueryOperators eOperator,
|
|
FLMUINT uiCompareRules,
|
|
FLMBOOL, // bNotted,
|
|
SQLBoolType * peBool)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMINT iCmp;
|
|
|
|
if (!pLValue || pLValue->eValType == SQL_MISSING_VAL ||
|
|
!pRValue || pRValue->eValType == SQL_MISSING_VAL ||
|
|
!sqlCanCompare( pLValue, pRValue))
|
|
{
|
|
*peBool = SQL_UNKNOWN;
|
|
}
|
|
|
|
// At this point, both operands are known to be present and are of
|
|
// types that can be compared. The comparison
|
|
// will therefore be performed according to the
|
|
// operator specified.
|
|
|
|
else
|
|
{
|
|
switch (eOperator)
|
|
{
|
|
case SQL_EQ_OP:
|
|
case SQL_NE_OP:
|
|
if (pLValue->eValType == SQL_UTF8_VAL ||
|
|
pRValue->eValType == SQL_UTF8_VAL)
|
|
{
|
|
if (RC_BAD( rc = sqlCompareText( pLValue, pRValue,
|
|
uiCompareRules, TRUE, uiLanguage, &iCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = sqlCompare( pLValue, pRValue,
|
|
uiCompareRules, uiLanguage, &iCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
if (eOperator == SQL_EQ_OP)
|
|
{
|
|
*peBool = (iCmp == 0 ? SQL_TRUE : SQL_FALSE);
|
|
}
|
|
else
|
|
{
|
|
*peBool = (iCmp != 0 ? SQL_TRUE : SQL_FALSE);
|
|
}
|
|
break;
|
|
|
|
case SQL_APPROX_EQ_OP:
|
|
if (RC_BAD( rc = sqlApproxCompare( pLValue, pRValue, &iCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
*peBool = (iCmp == 0 ? SQL_TRUE : SQL_FALSE);
|
|
break;
|
|
|
|
case SQL_LT_OP:
|
|
if (RC_BAD( rc = sqlCompare( pLValue, pRValue,
|
|
uiCompareRules, uiLanguage, &iCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
*peBool = (iCmp < 0 ? SQL_TRUE : SQL_FALSE);
|
|
break;
|
|
|
|
case SQL_LE_OP:
|
|
if (RC_BAD( rc = sqlCompare( pLValue, pRValue,
|
|
uiCompareRules, uiLanguage, &iCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
*peBool = (iCmp <= 0 ? SQL_TRUE : SQL_FALSE);
|
|
break;
|
|
|
|
case SQL_GT_OP:
|
|
if (RC_BAD( rc = sqlCompare( pLValue, pRValue,
|
|
uiCompareRules, uiLanguage, &iCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
*peBool = (iCmp > 0 ? SQL_TRUE : SQL_FALSE);
|
|
break;
|
|
|
|
case SQL_GE_OP:
|
|
if (RC_BAD( rc = sqlCompare( pLValue, pRValue,
|
|
uiCompareRules, uiLanguage, &iCmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
*peBool = (iCmp >= 0 ? SQL_TRUE : SQL_FALSE);
|
|
break;
|
|
|
|
default:
|
|
*peBool = SQL_UNKNOWN;
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_QUERY_SYNTAX);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Do an arithmetic operator.
|
|
***************************************************************************/
|
|
RCODE sqlEvalArithOperator(
|
|
SQL_VALUE * pLValue,
|
|
SQL_VALUE * pRValue,
|
|
eSQLQueryOperators eOperator,
|
|
SQL_VALUE * pResult)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
SQL_ARITH_OP * fnOp;
|
|
FLMUINT uiOffset = 0;
|
|
|
|
if (!isSQLArithOp( eOperator))
|
|
{
|
|
rc = RC_SET( NE_SFLM_Q_INVALID_OPERATOR);
|
|
goto Exit;
|
|
}
|
|
|
|
if (pLValue->eValType == SQL_MISSING_VAL ||
|
|
pRValue->eValType == SQL_MISSING_VAL)
|
|
{
|
|
pResult->eValType = SQL_MISSING_VAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if (isSQLValUnsigned( pLValue->eValType))
|
|
{
|
|
if (isSQLValUnsigned( pRValue->eValType))
|
|
{
|
|
uiOffset = 0;
|
|
}
|
|
else if (isSQLValSigned( pRValue->eValType))
|
|
{
|
|
uiOffset = 1;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (isSQLValSigned( pLValue->eValType))
|
|
{
|
|
if (isSQLValUnsigned( pRValue->eValType))
|
|
{
|
|
uiOffset = 2;
|
|
}
|
|
else if (isSQLValSigned( pRValue->eValType))
|
|
{
|
|
uiOffset = 3;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_SFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
fnOp = SQL_ArithOpTable[ ((((FLMUINT)eOperator) -
|
|
SQL_FIRST_ARITH_OP) * 4) + uiOffset];
|
|
fnOp( pLValue, pRValue, pResult);
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Get a column's value from the passed in row. Return it in pSqlValue.
|
|
***************************************************************************/
|
|
FSTATIC RCODE sqlGetColumnValue(
|
|
F_Db * pDb,
|
|
F_Row * pRow,
|
|
FLMUINT uiTableNum,
|
|
FLMUINT uiColumnNum,
|
|
F_Pool * pPool,
|
|
SQL_VALUE * pSqlValue)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
F_TABLE * pTable = pDb->getDict()->getTable( uiTableNum);
|
|
F_COLUMN * pColumn = pDb->getDict()->getColumn( pTable, uiColumnNum);
|
|
FLMBOOL bNeg;
|
|
FLMUINT64 ui64Value;
|
|
FLMBOOL bIsNull;
|
|
FLMUINT uiDataLen;
|
|
const FLMBYTE * pucColumnData;
|
|
const FLMBYTE * pucEnd;
|
|
|
|
flmAssert( pTable->uiTableNum == uiTableNum);
|
|
|
|
pRow->getDataLen( pDb, uiColumnNum, &uiDataLen, &bIsNull);
|
|
if (bIsNull)
|
|
{
|
|
pSqlValue->eValType = SQL_MISSING_VAL;
|
|
goto Exit;
|
|
}
|
|
pucColumnData = (const FLMBYTE *)pRow->getColumnDataPtr( uiColumnNum);
|
|
switch (pColumn->eDataTyp)
|
|
{
|
|
case SFLM_STRING_TYPE:
|
|
|
|
// Decode the number of characters directly from the column's
|
|
// data buffer. Then copy only whatever part remains after that.
|
|
|
|
pSqlValue->eValType = SQL_UTF8_VAL;
|
|
pucEnd = pucColumnData + uiDataLen;
|
|
if (RC_BAD( rc = f_decodeSEN( &pucColumnData, pucEnd,
|
|
&pSqlValue->val.str.uiNumChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
uiDataLen = (FLMUINT)(pucEnd - pucColumnData);
|
|
pSqlValue->val.str.uiByteLen = uiDataLen;
|
|
if (RC_BAD( rc = pPool->poolAlloc( uiDataLen,
|
|
(void **)&pSqlValue->val.str.pszStr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
f_memcpy( pSqlValue->val.str.pszStr, pucColumnData, uiDataLen);
|
|
break;
|
|
|
|
case SFLM_NUMBER_TYPE:
|
|
if (RC_BAD( rc = flmStorageNumberToNumber( pucColumnData, uiDataLen,
|
|
&ui64Value, &bNeg)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
if (!bNeg)
|
|
{
|
|
if (ui64Value <= (FLMUINT64)(FLM_MAX_UINT))
|
|
{
|
|
pSqlValue->eValType = SQL_UINT_VAL;
|
|
pSqlValue->val.uiVal = (FLMUINT)ui64Value;
|
|
}
|
|
else
|
|
{
|
|
pSqlValue->eValType = SQL_UINT64_VAL;
|
|
pSqlValue->val.ui64Val = ui64Value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (-((FLMINT64)ui64Value) <= (FLMINT64)(FLM_MIN_INT))
|
|
{
|
|
pSqlValue->eValType = SQL_INT_VAL;
|
|
pSqlValue->val.iVal = (FLMINT)(-((FLMINT64)ui64Value));
|
|
}
|
|
else
|
|
{
|
|
pSqlValue->eValType = SQL_INT64_VAL;
|
|
pSqlValue->val.i64Val = -((FLMINT64)ui64Value);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SFLM_BINARY_TYPE:
|
|
pSqlValue->eValType = SQL_BINARY_VAL;
|
|
if (RC_BAD( rc = pPool->poolAlloc( uiDataLen,
|
|
(void **)&pSqlValue->val.bin.pucValue)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pSqlValue->val.bin.uiByteLen = uiDataLen;
|
|
f_memcpy( pSqlValue->val.bin.pucValue, pucColumnData, uiDataLen);
|
|
break;
|
|
|
|
default:
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_SFLM_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Evaluate a simple operator.
|
|
***************************************************************************/
|
|
FSTATIC RCODE sqlEvalOperator(
|
|
FLMUINT uiLanguage,
|
|
SQL_NODE * pQNode)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
SQL_NODE * pLeftOperand;
|
|
SQL_NODE * pRightOperand;
|
|
SQLBoolType eBool;
|
|
|
|
// Right now we are only able to do operator nodes.
|
|
|
|
flmAssert( pQNode->eNodeType == SQL_OPERATOR_NODE);
|
|
|
|
pLeftOperand = pQNode->pFirstChild;
|
|
pRightOperand = pQNode->pLastChild;
|
|
|
|
pQNode->currVal.eValType = SQL_MISSING_VAL;
|
|
|
|
switch (pQNode->nd.op.eOperator)
|
|
{
|
|
case SQL_AND_OP:
|
|
case SQL_OR_OP:
|
|
pQNode->currVal.eValType = SQL_BOOL_VAL;
|
|
|
|
// There may be multiple operands here. We have already looked
|
|
// at all of the operands. If this is an AND we know that all
|
|
// of them were either TRUE or UNKNOWN. If this is an OR, we know
|
|
// that all of the previous operands were either FALSE or UNKNOWN.
|
|
// If we had hit a FALSE for an AND or a TRUE for an OR, we would
|
|
// not have come to this point. Now we just need to determine if
|
|
// any of the operands are UNKNOWN. If so, that is what we will
|
|
// set this node's value to. Otherwise, we will set it to TRUE for
|
|
// AND and FALSE for OR.
|
|
|
|
while (pLeftOperand)
|
|
{
|
|
|
|
// Get the left operand
|
|
|
|
if (pLeftOperand->eNodeType == SQL_OPERATOR_NODE)
|
|
{
|
|
|
|
// This operator may not have been evaluated because of missing
|
|
// column values in one or both operands, in which case
|
|
// its state will be SQL_MISSING_VALUE. If it was evaluated,
|
|
// its state should show a boolean value.
|
|
|
|
if (pLeftOperand->currVal.eValType == SQL_MISSING_VAL)
|
|
{
|
|
eBool = (pLeftOperand->bNotted ? SQL_TRUE : SQL_FALSE);
|
|
}
|
|
else
|
|
{
|
|
flmAssert( pLeftOperand->currVal.eValType == SQL_BOOL_VAL);
|
|
eBool = pLeftOperand->currVal.val.eBool;
|
|
}
|
|
}
|
|
else if (pLeftOperand->eNodeType == SQL_COLUMN_NODE)
|
|
{
|
|
if (!pLeftOperand->bNotted)
|
|
{
|
|
eBool = (pLeftOperand->currVal.eValType != SQL_MISSING_VAL)
|
|
? SQL_TRUE
|
|
: SQL_FALSE;
|
|
}
|
|
else
|
|
{
|
|
eBool = (pLeftOperand->currVal.eValType != SQL_MISSING_VAL)
|
|
? SQL_FALSE
|
|
: SQL_TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flmAssert( pLeftOperand->eNodeType == SQL_VALUE_NODE);
|
|
flmAssert( pLeftOperand->currVal.eValType == SQL_BOOL_VAL);
|
|
eBool = pLeftOperand->currVal.val.eBool;
|
|
}
|
|
|
|
// eBool better not have FALSE for an AND operator or
|
|
// TRUE for an OR operator.
|
|
|
|
flmAssert( (pQNode->nd.op.eOperator == SQL_AND_OP &&
|
|
eBool != SQL_FALSE) ||
|
|
(pQNode->nd.op.eOperator == SQL_OR_OP &&
|
|
eBool != SQL_TRUE));
|
|
|
|
|
|
if (eBool == SQL_UNKNOWN)
|
|
{
|
|
pQNode->currVal.val.eBool = SQL_UNKNOWN;
|
|
break;
|
|
}
|
|
pLeftOperand = pLeftOperand->pNextSib;
|
|
}
|
|
|
|
// If we didn't hit an UNKNOWN, set the node's value to TRUE for
|
|
// an AND operator and FALSE for an OR operator.
|
|
|
|
if (!pLeftOperand)
|
|
{
|
|
pQNode->currVal.val.eBool = pQNode->nd.op.eOperator == SQL_AND_OP
|
|
? SQL_TRUE
|
|
: SQL_FALSE;
|
|
}
|
|
break;
|
|
|
|
case SQL_EQ_OP:
|
|
case SQL_APPROX_EQ_OP:
|
|
case SQL_NE_OP:
|
|
case SQL_LT_OP:
|
|
case SQL_LE_OP:
|
|
case SQL_GT_OP:
|
|
case SQL_GE_OP:
|
|
pQNode->currVal.eValType = SQL_BOOL_VAL;
|
|
if (RC_BAD( rc = sqlCompareOperands( uiLanguage,
|
|
&pLeftOperand->currVal,
|
|
&pRightOperand->currVal,
|
|
pQNode->nd.op.eOperator,
|
|
pQNode->nd.op.uiCompareRules,
|
|
pQNode->bNotted,
|
|
&pQNode->currVal.val.eBool)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
break;
|
|
|
|
case SQL_BITAND_OP:
|
|
case SQL_BITOR_OP:
|
|
case SQL_BITXOR_OP:
|
|
case SQL_MULT_OP:
|
|
case SQL_DIV_OP:
|
|
case SQL_MOD_OP:
|
|
case SQL_PLUS_OP:
|
|
case SQL_MINUS_OP:
|
|
case SQL_NEG_OP:
|
|
|
|
if (RC_BAD( rc = sqlEvalArithOperator( &pLeftOperand->currVal,
|
|
&pRightOperand->currVal,
|
|
pQNode->nd.op.eOperator,
|
|
&pQNode->currVal)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Evaluate a query expression.
|
|
***************************************************************************/
|
|
RCODE sqlEvalCriteria(
|
|
F_Db * pDb,
|
|
SQL_NODE * pQueryExpr,
|
|
SQL_VALUE ** ppSqlValue,
|
|
F_Pool * pPool,
|
|
F_Row * pRow,
|
|
FLMUINT uiLanguage)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
SQL_NODE * pCurrNode;
|
|
SQL_VALUE * pSqlValue;
|
|
SQLBoolType eBoolVal;
|
|
SQLBoolType eBoolPartialEval;
|
|
|
|
// If the query is empty, return a value of SQL_TRUE.
|
|
|
|
if (!pQueryExpr)
|
|
{
|
|
if (RC_BAD( rc = pPool->poolAlloc( sizeof( SQL_VALUE),
|
|
(void **)ppSqlValue)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pSqlValue = *ppSqlValue;
|
|
pSqlValue->eValType = SQL_BOOL_VAL;
|
|
pSqlValue->uiFlags = SQL_VAL_IS_CONSTANT;
|
|
pSqlValue->val.eBool = SQL_TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
// If the query is a constant, return pointer to its value.
|
|
|
|
if (pQueryExpr->eNodeType == SQL_VALUE_NODE)
|
|
{
|
|
*ppSqlValue = &pQueryExpr->currVal;
|
|
goto Exit;
|
|
}
|
|
|
|
// If the query is a column, get the column's value from the
|
|
// row that was passed in.
|
|
|
|
if (pQueryExpr->eNodeType == SQL_COLUMN_NODE)
|
|
{
|
|
*ppSqlValue = &pQueryExpr->currVal;
|
|
rc = sqlGetColumnValue( pDb, pRow,
|
|
pQueryExpr->nd.column.pSQLTable->uiTableNum,
|
|
pQueryExpr->nd.column.uiColumnNum,
|
|
pPool, *ppSqlValue);
|
|
goto Exit;
|
|
}
|
|
|
|
// Perform the evaluation
|
|
|
|
pCurrNode = pQueryExpr;
|
|
for (;;)
|
|
{
|
|
while (pCurrNode->pFirstChild)
|
|
{
|
|
pCurrNode = pCurrNode->pFirstChild;
|
|
}
|
|
|
|
// We should be positioned on a leaf node that is either a
|
|
// value or a column
|
|
|
|
if (pCurrNode->eNodeType == SQL_COLUMN_NODE)
|
|
{
|
|
if (RC_BAD( rc = sqlGetColumnValue( pDb, pRow,
|
|
pCurrNode->nd.column.pSQLTable->uiTableNum,
|
|
pCurrNode->nd.column.uiColumnNum,
|
|
pPool, &pCurrNode->currVal)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Better be a constant
|
|
|
|
flmAssert( pCurrNode->eNodeType == SQL_VALUE_NODE);
|
|
}
|
|
|
|
// When we get to this point, we have at least one leaf
|
|
// level operand in hand - pCurrNode.
|
|
// See if we can evaluate the operator of pCurrNode.
|
|
// This will take care of any short-circuiting evaluation
|
|
// that can be done.
|
|
|
|
for (;;)
|
|
{
|
|
if (pCurrNode == pQueryExpr)
|
|
{
|
|
*ppSqlValue = &pQueryExpr->currVal;
|
|
goto Exit;
|
|
}
|
|
|
|
// If the current node's parent is an AND or OR
|
|
// operator, see if we even need to go to the next
|
|
// sibling.
|
|
|
|
flmAssert( pCurrNode->pParent->eNodeType == SQL_OPERATOR_NODE);
|
|
if (isSQLLogicalOp( pCurrNode->pParent->nd.op.eOperator))
|
|
{
|
|
// All NOT operators should have been weeded out of the tree
|
|
// by now.
|
|
|
|
flmAssert( pCurrNode->pParent->nd.op.eOperator != SQL_NOT_OP);
|
|
eBoolVal = SQL_UNKNOWN;
|
|
eBoolPartialEval = pCurrNode->pParent->nd.op.eOperator == SQL_AND_OP
|
|
? SQL_FALSE
|
|
: SQL_TRUE;
|
|
if (pCurrNode->eNodeType == SQL_OPERATOR_NODE)
|
|
{
|
|
|
|
// It may not have been evaluated because of missing
|
|
// values in one or both operands, in which case
|
|
// its state will be SQL_MISSING_VALUE. If it was
|
|
// evaluated, its state should show a boolean value.
|
|
|
|
if (pCurrNode->currVal.eValType == SQL_MISSING_VAL)
|
|
{
|
|
eBoolVal = (pCurrNode->bNotted ? SQL_TRUE : SQL_FALSE);
|
|
}
|
|
else
|
|
{
|
|
flmAssert( pCurrNode->currVal.eValType == SQL_BOOL_VAL);
|
|
eBoolVal = pCurrNode->currVal.val.eBool;
|
|
}
|
|
}
|
|
else if (pCurrNode->eNodeType == SQL_COLUMN_NODE)
|
|
{
|
|
if (!pCurrNode->bNotted)
|
|
{
|
|
eBoolVal = (pCurrNode->currVal.eValType == SQL_MISSING_VAL)
|
|
? SQL_FALSE
|
|
: SQL_TRUE;
|
|
}
|
|
else
|
|
{
|
|
eBoolVal = (pCurrNode->currVal.eValType == SQL_MISSING_VAL)
|
|
? SQL_TRUE
|
|
: SQL_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flmAssert( pCurrNode->eNodeType == SQL_VALUE_NODE);
|
|
|
|
// Only allowed value node underneath a logical operator is
|
|
// a boolean value that has a value of SQL_UNKNOWN.
|
|
// SQL_FALSE and SQL_TRUE will already have been weeded out.
|
|
|
|
flmAssert( pCurrNode->currVal.eValType == SQL_BOOL_VAL &&
|
|
pCurrNode->currVal.val.eBool == SQL_UNKNOWN);
|
|
|
|
// No need to set eBoolVal to SQL_UNKNOWN, because it will never
|
|
// match eBoolPartialEval in the test below. eBoolPartialEval
|
|
// is always either SQL_FALSE or SQL_TRUE.
|
|
|
|
// eBoolVal = SQL_UNKNOWN;
|
|
|
|
}
|
|
if (eBoolVal == eBoolPartialEval)
|
|
{
|
|
pCurrNode = pCurrNode->pParent;
|
|
pCurrNode->currVal.eValType = SQL_BOOL_VAL;
|
|
pCurrNode->currVal.val.eBool = eBoolVal;
|
|
}
|
|
else
|
|
{
|
|
goto Check_Sibling_Operand;
|
|
}
|
|
}
|
|
else if (isSQLCompareOp( pCurrNode->pParent->nd.op.eOperator))
|
|
{
|
|
|
|
// We can short-circuit the comparison - avoid getting the
|
|
// sibling operand - if the current node is a missing value.
|
|
// If the value is missing, the comparison operator will
|
|
// return a boolean SQL_UNKNOWN, regardless of what the
|
|
// other operand is.
|
|
|
|
if (pCurrNode->currVal.eValType == SQL_MISSING_VAL)
|
|
{
|
|
pCurrNode = pCurrNode->pParent;
|
|
pCurrNode->currVal.eValType = SQL_BOOL_VAL;
|
|
pCurrNode->currVal.val.eBool = SQL_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
goto Check_Sibling_Operand;
|
|
}
|
|
}
|
|
else if (isSQLArithOp( pCurrNode->pParent->nd.op.eOperator))
|
|
{
|
|
|
|
// We can short-circuit the arithmetic operation - avoid getting the
|
|
// sibling operand - if the current node is a missing value.
|
|
// If the value is missing, the arithmetic operation will
|
|
// return a missing value, regardless of what the
|
|
// other operand is.
|
|
|
|
if (pCurrNode->currVal.eValType == SQL_MISSING_VAL)
|
|
{
|
|
pCurrNode = pCurrNode->pParent;
|
|
pCurrNode->currVal.eValType = SQL_MISSING_VAL;
|
|
}
|
|
else
|
|
{
|
|
goto Check_Sibling_Operand;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
Check_Sibling_Operand:
|
|
|
|
if (pCurrNode->pNextSib)
|
|
{
|
|
pCurrNode = pCurrNode->pNextSib;
|
|
break;
|
|
}
|
|
pCurrNode = pCurrNode->pParent;
|
|
|
|
// All operands are now present - do evaluation
|
|
|
|
if (RC_BAD( rc = sqlEvalOperator( uiLanguage, pCurrNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|