//------------------------------------------------------------------------------ // Desc: Contains the methods for doing evaluation of query expressions. // // Tabs: 3 // // Copyright (c) 2003-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 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $ //------------------------------------------------------------------------------ #include "flaimsys.h" #include "fquery.h" FSTATIC RCODE fqApproxCompare( FQVALUE * pLValue, FQVALUE * pRValue, FLMINT * piResult); FSTATIC RCODE fqCompareBinary( IF_OperandComparer * pOpComparer, FQVALUE * pLValue, FQVALUE * pRValue, FLMINT * piResult); FSTATIC RCODE fqCompareText( IF_OperandComparer * pOpComparer, FQVALUE * pLValue, FQVALUE * pRValue, FLMUINT uiCompareRules, FLMBOOL bOpIsMatch, FLMUINT uiLanguage, FLMINT * piResult); FSTATIC void fqOpUUBitAND( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUUBitOR( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUUBitXOR( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUUMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUSMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSSMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSUMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUUDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUSDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSSDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSUDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUUMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUSMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSSMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSUMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUUPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUSPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSSPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSUPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUUMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpUSMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSSMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FSTATIC void fqOpSUMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); typedef void FQ_OPERATION( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult); FQ_OPERATION * FQ_ArithOpTable[ ((XFLM_LAST_ARITH_OP - XFLM_FIRST_ARITH_OP) + 1) * 4 ] = { /* U = Unsigned S = Signed U + U U + S S + U S + S */ /* BITAND */ fqOpUUBitAND, fqOpUUBitAND, fqOpUUBitAND, fqOpUUBitAND, /* BITOR */ fqOpUUBitOR, fqOpUUBitOR, fqOpUUBitOR, fqOpUUBitOR, /* BITXOR */ fqOpUUBitXOR, fqOpUUBitXOR, fqOpUUBitXOR, fqOpUUBitXOR, /* MULT */ fqOpUUMult, fqOpUSMult, fqOpSUMult, fqOpSSMult, /* DIV */ fqOpUUDiv, fqOpUSDiv, fqOpSUDiv, fqOpSSDiv, /* MOD */ fqOpUUMod, fqOpUSMod, fqOpSUMod, fqOpSSMod, /* PLUS */ fqOpUUPlus, fqOpUSPlus, fqOpSUPlus, fqOpSSPlus, /* MINUS */ fqOpUUMinus, fqOpUSMinus, fqOpSUMinus, fqOpSSMinus }; /*************************************************************************** Desc: Returns a 64-bit unsigned integer ***************************************************************************/ FINLINE FLMUINT64 fqGetUInt64( FQVALUE * pValue) { if (pValue->eValType == XFLM_UINT_VAL) { return( (FLMUINT64)pValue->val.uiVal); } else if( pValue->eValType == XFLM_UINT64_VAL) { return( pValue->val.ui64Val); } else if( pValue->eValType == XFLM_INT64_VAL) { if( pValue->val.i64Val >= 0) { return( (FLMUINT64)pValue->val.i64Val); } } else if( pValue->eValType == XFLM_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 fqGetInt64( FQVALUE * pValue) { if (pValue->eValType == XFLM_INT_VAL) { return( (FLMINT64)pValue->val.iVal); } else if( pValue->eValType == XFLM_INT64_VAL) { return( pValue->val.i64Val); } else if( pValue->eValType == XFLM_UINT_VAL) { return( (FLMINT64)pValue->val.uiVal); } else if( pValue->eValType == XFLM_UINT64_VAL) { if( pValue->val.ui64Val <= (FLMUINT64)FLM_MAX_INT64) { return( (FLMINT64)pValue->val.ui64Val); } } flmAssert( 0); return( 0); } /*************************************************************************** Desc: Performs the bit and operation ***************************************************************************/ FSTATIC void fqOpUUBitAND( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.uiVal = pLValue->val.uiVal & pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.ui64Val = fqGetUInt64( pLValue) & fqGetUInt64( pRValue); pResult->eValType = XFLM_UINT64_VAL; } } /*************************************************************************** Desc: Performs the bit or operation ***************************************************************************/ FSTATIC void fqOpUUBitOR( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.uiVal = pLValue->val.uiVal | pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.ui64Val = fqGetUInt64( pLValue) | fqGetUInt64( pRValue); pResult->eValType = XFLM_UINT64_VAL; } } /*************************************************************************** Desc: Performs the bit xor operation ***************************************************************************/ FSTATIC void fqOpUUBitXOR( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.uiVal = pLValue->val.uiVal ^ pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.ui64Val = fqGetUInt64( pLValue) ^ fqGetUInt64( pRValue); pResult->eValType = XFLM_UINT64_VAL; } } /*************************************************************************** Desc: Performs the multiply operation ***************************************************************************/ FSTATIC void fqOpUUMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.uiVal = pLValue->val.uiVal * pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.ui64Val = fqGetUInt64( pLValue) * fqGetUInt64( pRValue); pResult->eValType = XFLM_UINT64_VAL; } } /*************************************************************************** Desc: Performs the multiply operation ***************************************************************************/ FSTATIC void fqOpUSMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.iVal = (FLMINT)pLValue->val.uiVal * pRValue->val.iVal; pResult->eValType = XFLM_INT_VAL; } else { pResult->val.i64Val = (FLMINT64) fqGetUInt64( pLValue) * fqGetInt64( pRValue); pResult->eValType = XFLM_INT64_VAL; } } /*************************************************************************** Desc: Performs the multiply operation ***************************************************************************/ FSTATIC void fqOpSSMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.iVal = pLValue->val.iVal * pRValue->val.iVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } else { pResult->val.i64Val = (FLMINT64)(fqGetInt64( pLValue) * fqGetInt64( pRValue)); pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } } /*************************************************************************** Desc: Performs the multiply operation ***************************************************************************/ FSTATIC void fqOpSUMult( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.iVal = pLValue->val.iVal * (FLMINT)pRValue->val.uiVal; pResult->eValType = XFLM_INT_VAL; } else { pResult->val.i64Val = (FLMINT64) (fqGetInt64( pLValue) * fqGetUInt64( pRValue)); pResult->eValType = XFLM_INT64_VAL; } } /*************************************************************************** Desc: Performs the divide operation ***************************************************************************/ FSTATIC void fqOpUUDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.uiVal) { pResult->val.uiVal = pLValue->val.uiVal / pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMUINT64 ui64LValue = fqGetUInt64( pLValue); FLMUINT64 ui64RValue = fqGetUInt64( pRValue); if( ui64RValue) { pResult->val.ui64Val = ui64LValue / ui64RValue; pResult->eValType = XFLM_UINT64_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs the divide operation ***************************************************************************/ FSTATIC void fqOpUSDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.iVal) { pResult->val.iVal = pLValue->val.uiVal / pRValue->val.iVal; pResult->eValType = XFLM_INT_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMUINT64 ui64LValue = fqGetUInt64( pLValue); FLMINT64 i64RValue = fqGetInt64( pRValue); if( i64RValue) { pResult->val.i64Val = ui64LValue / i64RValue; pResult->eValType = XFLM_INT64_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs the divide operation ***************************************************************************/ FSTATIC void fqOpSSDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.iVal) { pResult->val.iVal = pLValue->val.iVal / pRValue->val.iVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMINT64 i64LValue = fqGetInt64( pLValue); FLMINT64 i64RValue = fqGetInt64( pRValue); if( i64RValue) { pResult->val.i64Val = i64LValue / i64RValue; pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs the divide operation ***************************************************************************/ FSTATIC void fqOpSUDiv( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.uiVal) { pResult->val.iVal = pLValue->val.iVal / pRValue->val.uiVal; pResult->eValType = XFLM_INT_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMINT64 i64LValue = fqGetInt64( pLValue); FLMUINT64 ui64RValue = fqGetUInt64( pRValue); if( ui64RValue) { pResult->val.i64Val = i64LValue / ui64RValue; pResult->eValType = XFLM_INT64_VAL; } else { pResult->val.uiVal = 0; // Divide by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs the modulo operation ***************************************************************************/ FSTATIC void fqOpUUMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.uiVal) { pResult->val.uiVal = pLValue->val.uiVal % pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMUINT64 ui64LValue = fqGetUInt64( pLValue); FLMUINT64 ui64RValue = fqGetUInt64( pRValue); if( ui64RValue) { pResult->val.ui64Val = ui64LValue % ui64RValue; pResult->eValType = XFLM_UINT64_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs the modulo operation ***************************************************************************/ FSTATIC void fqOpUSMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.iVal) { pResult->val.iVal = pLValue->val.uiVal % pRValue->val.iVal; pResult->eValType = XFLM_INT_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMUINT64 ui64LValue = fqGetUInt64( pLValue); FLMINT64 i64RValue = fqGetInt64( pRValue); if( i64RValue) { pResult->val.i64Val = ui64LValue % i64RValue; pResult->eValType = XFLM_INT64_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs the modulo operation ***************************************************************************/ FSTATIC void fqOpSSMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.iVal) { pResult->val.iVal = pLValue->val.iVal % pRValue->val.iVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMINT64 i64LValue = fqGetInt64( pLValue); FLMINT64 i64RValue = fqGetInt64( pRValue); if( i64RValue) { pResult->val.i64Val = i64LValue % i64RValue; pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs the modulo operation ***************************************************************************/ FSTATIC void fqOpSUMod( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.uiVal) { pResult->val.iVal = pLValue->val.iVal % pRValue->val.uiVal; pResult->eValType = XFLM_INT_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } else { FLMINT64 i64LValue = fqGetInt64( pLValue); FLMUINT64 ui64RValue = fqGetUInt64( pRValue); if( ui64RValue) { pResult->val.i64Val = i64LValue % ui64RValue; pResult->eValType = XFLM_INT64_VAL; } else { pResult->val.uiVal = 0; // MOD by ZERO case. pResult->eValType = XFLM_MISSING_VAL; } } } /*************************************************************************** Desc: Performs an addition operation ***************************************************************************/ FSTATIC void fqOpUUPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.uiVal = pLValue->val.uiVal + pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.ui64Val = fqGetUInt64( pLValue) + fqGetUInt64( pRValue); pResult->eValType = XFLM_UINT64_VAL; } } /*************************************************************************** Desc: Performs an addition operation ***************************************************************************/ FSTATIC void fqOpUSPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( (pRValue->val.iVal >= 0) || (pLValue->val.uiVal > gv_uiMaxSignedIntVal)) { pResult->val.uiVal = pLValue->val.uiVal + (FLMUINT)pRValue->val.iVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.iVal = (FLMINT)pLValue->val.uiVal + pRValue->val.iVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } } else { FLMUINT64 ui64LValue = fqGetUInt64( pLValue); FLMINT64 i64RValue = fqGetInt64( pRValue); if( (i64RValue >= 0) || (ui64LValue > gv_ui64MaxSignedIntVal)) { pResult->val.ui64Val = ui64LValue + (FLMUINT64)i64RValue; pResult->eValType = XFLM_UINT64_VAL; } else { pResult->val.i64Val = (FLMINT64)ui64LValue + i64RValue; pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } } } /*************************************************************************** Desc: Performs an addition operation ***************************************************************************/ FSTATIC void fqOpSSPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { pResult->val.iVal = pLValue->val.iVal + pRValue->val.iVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } else { pResult->val.i64Val = fqGetInt64( pLValue) + fqGetInt64( pRValue); pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } } /*************************************************************************** Desc: Performs an addition operation ***************************************************************************/ FSTATIC void fqOpSUPlus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( (pLValue->val.iVal >= 0) || (pRValue->val.uiVal > gv_uiMaxSignedIntVal)) { pResult->val.uiVal = (FLMUINT)pLValue->val.iVal + pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.iVal = pLValue->val.iVal + (FLMINT)pRValue->val.uiVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } } else { FLMINT64 i64LValue = fqGetInt64( pLValue); FLMUINT64 ui64RValue = fqGetUInt64( pRValue); if( (i64LValue >= 0) || (ui64RValue > gv_ui64MaxSignedIntVal)) { pResult->val.ui64Val = (FLMUINT64)i64LValue + ui64RValue; pResult->eValType = XFLM_UINT64_VAL; } else { pResult->val.i64Val = i64LValue + (FLMINT64)ui64RValue; pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } } } /*************************************************************************** Desc: Performs a subtraction operation ***************************************************************************/ FSTATIC void fqOpUUMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pLValue->val.uiVal >= pRValue->val.uiVal) { pResult->val.uiVal = pLValue->val.uiVal - pRValue->val.uiVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.iVal = (FLMINT)(pLValue->val.uiVal - pRValue->val.uiVal); pResult->eValType = XFLM_INT_VAL; } } else { FLMUINT64 ui64LValue = fqGetUInt64( pLValue); FLMUINT64 ui64RValue = fqGetUInt64( pRValue); if( ui64LValue >= ui64RValue) { pResult->val.ui64Val = ui64LValue - ui64RValue; pResult->eValType = XFLM_UINT64_VAL; } else { pResult->val.i64Val = (FLMINT64)(ui64LValue - ui64RValue); pResult->eValType = XFLM_INT64_VAL; } } } /*************************************************************************** Desc: Performs a subtraction operation ***************************************************************************/ FSTATIC void fqOpUSMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.iVal < 0) { pResult->val.uiVal = pLValue->val.uiVal - pRValue->val.iVal; pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.iVal = (FLMINT)pLValue->val.uiVal - pRValue->val.iVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } } else { FLMUINT64 ui64LValue = fqGetUInt64( pLValue); FLMINT64 i64RValue = fqGetInt64( pRValue); if( i64RValue < 0) { pResult->val.ui64Val = ui64LValue - i64RValue; pResult->eValType = XFLM_UINT64_VAL; } else { pResult->val.i64Val = (FLMINT64)ui64LValue - i64RValue; pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } } } /*************************************************************************** Desc: Performs a subtraction operation ***************************************************************************/ FSTATIC void fqOpSSMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if(( pLValue->val.iVal > 0) && ( pRValue->val.iVal < 0)) { pResult->val.uiVal = (FLMUINT)(pLValue->val.iVal - pRValue->val.iVal); pResult->eValType = XFLM_UINT_VAL; } else { pResult->val.iVal = pLValue->val.iVal - pRValue->val.iVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } } else { FLMINT64 i64LValue = fqGetInt64( pLValue); FLMINT64 i64RValue = fqGetInt64( pRValue); if( (i64LValue > 0) && (i64RValue < 0)) { pResult->val.ui64Val = (FLMUINT64)( i64LValue - i64RValue); pResult->eValType = XFLM_UINT64_VAL; } else { pResult->val.i64Val = i64LValue - i64RValue; pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } } } /*************************************************************************** Desc: Performs a subtraction operation ***************************************************************************/ FSTATIC void fqOpSUMinus( FQVALUE * pLValue, FQVALUE * pRValue, FQVALUE * pResult) { if( isNativeNum( pLValue->eValType) && isNativeNum( pRValue->eValType)) { if( pRValue->val.uiVal > gv_uiMaxSignedIntVal) { pResult->val.iVal = (pLValue->val.iVal - gv_uiMaxSignedIntVal) - (FLMINT)(pRValue->val.uiVal - gv_uiMaxSignedIntVal); pResult->eValType = XFLM_INT_VAL; } else { pResult->val.iVal = pLValue->val.iVal - (FLMINT)pRValue->val.uiVal; pResult->eValType = (pResult->val.iVal < 0) ? XFLM_INT_VAL : XFLM_UINT_VAL; } } else { FLMINT64 i64LValue = fqGetInt64( pLValue); FLMUINT64 ui64RValue = fqGetUInt64( pRValue); if( ui64RValue > gv_ui64MaxSignedIntVal) { pResult->val.i64Val = (i64LValue - gv_ui64MaxSignedIntVal) - (FLMINT64)(ui64RValue - gv_ui64MaxSignedIntVal); pResult->eValType = XFLM_INT64_VAL; } else { pResult->val.i64Val = i64LValue - (FLMINT64)ui64RValue; pResult->eValType = (pResult->val.i64Val < 0) ? XFLM_INT64_VAL : XFLM_UINT64_VAL; } } } /*************************************************************************** Desc: Compare two entire strings. ****************************************************************************/ RCODE fqCompareCollStreams( F_CollIStream * pLStream, F_CollIStream * pRStream, FLMBOOL bOpIsMatch, FLMUINT uiLanguage, FLMINT * piResult) { RCODE rc = NE_XFLM_OK; FLMUINT16 ui16RCol; FLMUINT16 ui16LCol; FLMUINT16 ui16RSubCol; FLMUINT16 ui16LSubCol; FLMBYTE ucRCase; FLMBYTE ucLCase; F_CollStreamPos savedRPos; F_CollStreamPos savedLPos; F_CollStreamPos startLPos; FLMUNICODE uLChar = 0; FLMBOOL bLCharIsWild = FALSE; FLMUNICODE uRChar = 0; FLMBOOL bRCharIsWild = FALSE; FLMBOOL bPrevLWasWild = FALSE; FLMBOOL bPrevRWasWild = FALSE; FLMBOOL bAllowTwoIntoOne; // If we are doing a "match" operation, we don't want two // character sequences like Ch, ae, etc. turned into a single // a single collation, because then matches that involve wildcards // like "aetna == a*" would not match properly. // When not doing a match operation, we WANT two character sequences // turned into a single collation value so that we can know if // something is > or <. When doing match operations, all we care // about is if they are equal or not, so there is no need to look // at double character collation properties. bAllowTwoIntoOne = bOpIsMatch ? FALSE : TRUE; for( ;;) { GetNextLChar: if( bLCharIsWild) { bPrevLWasWild = TRUE; } pLStream->getCurrPosition( &startLPos); if( RC_BAD( rc = pLStream->read( bAllowTwoIntoOne, &uLChar, &bLCharIsWild, &ui16LCol, &ui16LSubCol, &ucLCase))) { if( rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; // If the last character was a wildcard, we have a match! if( bPrevLWasWild) { *piResult = 0; goto Exit; } for( ;;) { if( RC_BAD( rc = pRStream->read( bAllowTwoIntoOne, &uRChar, &bRCharIsWild, &ui16RCol, &ui16RSubCol, &ucRCase))) { if( rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; *piResult = 0; } goto Exit; } // Break out when we hit a non-wild character if( !bRCharIsWild) { break; } } *piResult = -1; } goto Exit; } if( bLCharIsWild) { // Consume multiple wildcards if( bPrevLWasWild) { goto GetNextLChar; } // See if we match anywhere on the remaining right string for( ;;) { pRStream->getCurrPosition( &savedRPos); pLStream->getCurrPosition( &savedLPos); if( RC_BAD( rc = fqCompareCollStreams( pLStream, pRStream, bOpIsMatch, uiLanguage, piResult))) { goto Exit; } if( !(*piResult)) { goto Exit; } if( RC_BAD( rc = pRStream->positionTo( &savedRPos))) { goto Exit; } if( RC_BAD( rc = pRStream->read( bAllowTwoIntoOne, NULL, NULL, NULL, NULL, NULL))) { if( rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; break; } goto Exit; } if( RC_BAD( rc = pLStream->positionTo( &savedLPos))) { goto Exit; } } *piResult = 1; goto Exit; } GetNextRChar: if( bRCharIsWild) { bPrevRWasWild = TRUE; } if( RC_BAD( rc = pRStream->read( bAllowTwoIntoOne, &uRChar, &bRCharIsWild, &ui16RCol, &ui16RSubCol, &ucRCase))) { if( rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; // If the last character was a wildcard, we have a match! if( bPrevRWasWild) { *piResult = 0; } else { *piResult = 1; } } goto Exit; } if( bRCharIsWild) { if( bPrevRWasWild) { goto GetNextRChar; } // See if we match anywhere on the remaining left string if( RC_BAD( rc = pLStream->positionTo( &startLPos))) { goto Exit; } for( ;;) { pLStream->getCurrPosition( &savedLPos); pRStream->getCurrPosition( &savedRPos); if( RC_BAD( rc = fqCompareCollStreams( pLStream, pRStream, bOpIsMatch, uiLanguage, piResult))) { goto Exit; } if( !(*piResult)) { goto Exit; } if( RC_BAD( rc = pRStream->positionTo( &savedRPos))) { goto Exit; } if( RC_BAD( rc = pLStream->positionTo( &savedLPos))) { goto Exit; } // Skip the character we just processed if( RC_BAD( rc = pLStream->read( bAllowTwoIntoOne, NULL, NULL, NULL, NULL, NULL))) { if( rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; break; } goto Exit; } } *piResult = -1; goto Exit; } if( ui16LCol != ui16RCol) { *piResult = ui16LCol < ui16RCol ? -1 : 1; goto Exit; } else if( ui16LSubCol != ui16RSubCol) { *piResult = ui16LSubCol < ui16RSubCol ? -1 : 1; goto Exit; } else if( ucLCase != ucRCase) { // NOTE: If we are doing a case insensitive comparison, // ucLCase and ucRCase should be equal (both will have been // set to zero *piResult = ucLCase < ucRCase ? -1 : 1; goto Exit; } } Exit: return( rc); } /*************************************************************************** Desc: Compare two entire strings. ****************************************************************************/ FSTATIC RCODE fqCompareText( IF_OperandComparer * pOpComparer, FQVALUE * pLValue, FQVALUE * pRValue, FLMUINT uiCompareRules, FLMBOOL bOpIsMatch, FLMUINT uiLanguage, FLMINT * piResult) { RCODE rc = NE_XFLM_OK; F_BufferIStream bufferLStream; IF_PosIStream * pLStream; F_BufferIStream bufferRStream; IF_PosIStream * pRStream; F_CollIStream lStream; F_CollIStream rStream; // Types must be text if (pLValue->eValType != XFLM_UTF8_VAL || pRValue->eValType != XFLM_UTF8_VAL) { rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); goto Exit; } // Open the streams if( !(pLValue->uiFlags & VAL_IS_STREAM)) { if (RC_BAD( rc = bufferLStream.open( pLValue->val.pucBuf, pLValue->uiDataLen))) { goto Exit; } pLStream = &bufferLStream; } else { pLStream = pLValue->val.pIStream; } if( !(pRValue->uiFlags & VAL_IS_STREAM)) { if( RC_BAD( rc = bufferRStream.open( pRValue->val.pucBuf, pRValue->uiDataLen))) { goto Exit; } pRStream = &bufferRStream; } else { pRStream = pRValue->val.pIStream; } if (pOpComparer) { rc = pOpComparer->compare( pLStream, pRStream, piResult); goto Exit; } // Open up the collated streams if (RC_BAD( rc = lStream.open( pLStream, FALSE, uiLanguage, uiCompareRules, (bOpIsMatch && (pLValue->uiFlags & VAL_IS_CONSTANT)) ? TRUE : FALSE))) { goto Exit; } if (RC_BAD( rc = rStream.open( pRStream, FALSE, uiLanguage, uiCompareRules, (bOpIsMatch && (pRValue->uiFlags & VAL_IS_CONSTANT)) ? TRUE : FALSE))) { goto Exit; } if (RC_BAD( rc = fqCompareCollStreams( &lStream, &rStream, bOpIsMatch, uiLanguage, piResult))) { goto Exit; } Exit: return( rc); } /*************************************************************************** Desc: Approximate compare - only works for strings right now. ****************************************************************************/ FSTATIC RCODE fqApproxCompare( FQVALUE * pLValue, FQVALUE * pRValue, FLMINT * piResult) { RCODE rc = NE_XFLM_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 != XFLM_UTF8_VAL || pRValue->eValType != XFLM_UTF8_VAL) { rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); goto Exit; } // Open the streams if (!(pLValue->uiFlags & VAL_IS_STREAM)) { if (RC_BAD( rc = bufferLStream.open( pLValue->val.pucBuf, pLValue->uiDataLen))) { goto Exit; } pLStream = &bufferLStream; } else { pLStream = pLValue->val.pIStream; } if (!(pRValue->uiFlags & VAL_IS_STREAM)) { if( RC_BAD( rc = bufferRStream.open( pRValue->val.pucBuf, pRValue->uiDataLen))) { goto Exit; } pRStream = &bufferRStream; } else { pRStream = pRValue->val.pIStream; } if ((pLValue->uiFlags & VAL_IS_CONSTANT) || !(pRValue->uiFlags & VAL_IS_CONSTANT)) { for( ;;) { if( RC_BAD( rc = flmGetNextMetaphone( pLStream, &uiLMeta))) { if( rc == NE_XFLM_EOF_HIT) { *piResult = 0; rc = NE_XFLM_OK; } goto Exit; } ui64StartPos = pRStream->getCurrPosition(); for( ;;) { if( RC_BAD( rc = flmGetNextMetaphone( pRStream, &uiRMeta))) { if( rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; *piResult = -1; } goto Exit; } if( uiLMeta == uiRMeta) { break; } } if( RC_BAD( rc = pRStream->positionTo( ui64StartPos))) { goto Exit; } } } else { for( ;;) { if( RC_BAD( rc = flmGetNextMetaphone( pRStream, &uiRMeta))) { if( rc == NE_XFLM_EOF_HIT) { *piResult = 0; rc = NE_XFLM_OK; } goto Exit; } ui64StartPos = pLStream->getCurrPosition(); for( ;;) { if( RC_BAD( rc = flmGetNextMetaphone( pLStream, &uiLMeta))) { if( rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_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 XFLM_TRUE or XFLM_FALSE. ***************************************************************************/ FSTATIC RCODE fqCompareBinary( IF_OperandComparer * pOpComparer, FQVALUE * pLValue, FQVALUE * pRValue, FLMINT * piResult) { RCODE rc = NE_XFLM_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 != XFLM_BINARY_VAL || pRValue->eValType != XFLM_BINARY_VAL) { rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); goto Exit; } // Open the streams if( !(pLValue->uiFlags & VAL_IS_STREAM)) { if (RC_BAD( rc = bufferLStream.open( pLValue->val.pucBuf, pLValue->uiDataLen))) { goto Exit; } pLStream = &bufferLStream; } else { pLStream = pLValue->val.pIStream; } if( !(pRValue->uiFlags & VAL_IS_STREAM)) { if( RC_BAD( rc = bufferRStream.open( pRValue->val.pucBuf, pRValue->uiDataLen))) { goto Exit; } pRStream = &bufferRStream; } else { pRStream = pRValue->val.pIStream; } if (pOpComparer) { rc = pOpComparer->compare( pLStream, pRStream, piResult); goto Exit; } for (;;) { if (RC_BAD( rc = flmReadStorageAsBinary( pLStream, &ucLByte, 1, uiOffset, NULL))) { if (rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; bLEmpty = TRUE; } else { goto Exit; } } if (RC_BAD( rc = flmReadStorageAsBinary( pRStream, &ucRByte, 1, uiOffset, NULL))) { if (rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_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 fqCompare( FQVALUE * pValue1, FQVALUE * pValue2, FLMUINT uiCompareRules, IF_OperandComparer * pOpComparer, FLMUINT uiLanguage, FLMINT * piCmp) { RCODE rc = NE_XFLM_OK; // We have already called fqCanCompare, so no need to do it here switch (pValue1->eValType) { case XFLM_BOOL_VAL: *piCmp = pValue1->val.eBool > pValue2->val.eBool ? 1 : pValue1->val.eBool < pValue2->val.eBool ? -1 : 0; break; case XFLM_UINT_VAL: switch (pValue2->eValType) { case XFLM_UINT_VAL: *piCmp = pValue1->val.uiVal > pValue2->val.uiVal ? 1 : pValue1->val.uiVal < pValue2->val.uiVal ? -1 : 0; break; case XFLM_UINT64_VAL: *piCmp = (FLMUINT64)pValue1->val.uiVal > pValue2->val.ui64Val ? 1 : (FLMUINT64)pValue1->val.uiVal < pValue2->val.ui64Val ? -1 : 0; break; case XFLM_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 XFLM_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_XFLM_NOT_IMPLEMENTED); goto Exit; } break; case XFLM_UINT64_VAL: switch (pValue2->eValType) { case XFLM_UINT_VAL: *piCmp = pValue1->val.ui64Val > (FLMUINT64)pValue2->val.uiVal ? 1 : pValue1->val.ui64Val < (FLMUINT64)pValue2->val.uiVal ? -1 : 0; break; case XFLM_UINT64_VAL: *piCmp = pValue1->val.ui64Val > pValue2->val.ui64Val ? 1 : pValue1->val.ui64Val < pValue2->val.ui64Val ? -1 : 0; break; case XFLM_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 XFLM_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_XFLM_NOT_IMPLEMENTED); goto Exit; } break; case XFLM_INT_VAL: switch (pValue2->eValType) { case XFLM_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 XFLM_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 XFLM_INT_VAL: *piCmp = pValue1->val.iVal < pValue2->val.iVal ? -1 : pValue1->val.iVal > pValue2->val.iVal ? 1 : 0; break; case XFLM_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_XFLM_NOT_IMPLEMENTED); goto Exit; } break; case XFLM_INT64_VAL: switch (pValue2->eValType) { case XFLM_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 XFLM_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 XFLM_INT_VAL: *piCmp = pValue1->val.i64Val < (FLMINT64)pValue2->val.iVal ? -1 : pValue1->val.i64Val > (FLMINT64)pValue2->val.iVal ? 1 : 0; break; case XFLM_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_XFLM_NOT_IMPLEMENTED); goto Exit; } break; case XFLM_BINARY_VAL: if (RC_BAD( rc = fqCompareBinary( pOpComparer, pValue1, pValue2, piCmp))) { goto Exit; } break; case XFLM_UTF8_VAL: if (RC_BAD( rc = fqCompareText( pOpComparer, pValue1, pValue2, uiCompareRules, FALSE, uiLanguage, piCmp))) { goto Exit; } break; default: break; } Exit: return( rc); } /*************************************************************************** Desc: Do a comparison operator. ***************************************************************************/ RCODE fqCompareOperands( FLMUINT uiLanguage, FQVALUE * pLValue, FQVALUE * pRValue, eQueryOperators eOperator, FLMUINT uiCompareRules, IF_OperandComparer * pOpComparer, FLMBOOL bNotted, XFlmBoolType * peBool) { RCODE rc = NE_XFLM_OK; FLMINT iCmp; if (!pLValue || pLValue->eValType == XFLM_MISSING_VAL || !pRValue || pRValue->eValType == XFLM_MISSING_VAL || !fqCanCompare( pLValue, pRValue)) { *peBool = (bNotted ? XFLM_TRUE : XFLM_FALSE); } // 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 XFLM_EQ_OP: case XFLM_NE_OP: if (pLValue->eValType == XFLM_UTF8_VAL || pRValue->eValType == XFLM_UTF8_VAL) { if (RC_BAD( rc = fqCompareText( pOpComparer, pLValue, pRValue, uiCompareRules, TRUE, uiLanguage, &iCmp))) { goto Exit; } } else { if (RC_BAD( rc = fqCompare( pLValue, pRValue, uiCompareRules, pOpComparer, uiLanguage, &iCmp))) { goto Exit; } } if (eOperator == XFLM_EQ_OP) { *peBool = (iCmp == 0 ? XFLM_TRUE : XFLM_FALSE); } else { *peBool = (iCmp != 0 ? XFLM_TRUE : XFLM_FALSE); } break; case XFLM_APPROX_EQ_OP: if (RC_BAD( rc = fqApproxCompare( pLValue, pRValue, &iCmp))) { goto Exit; } *peBool = (iCmp == 0 ? XFLM_TRUE : XFLM_FALSE); break; case XFLM_LT_OP: if (RC_BAD( rc = fqCompare( pLValue, pRValue, uiCompareRules, pOpComparer, uiLanguage, &iCmp))) { goto Exit; } *peBool = (iCmp < 0 ? XFLM_TRUE : XFLM_FALSE); break; case XFLM_LE_OP: if (RC_BAD( rc = fqCompare( pLValue, pRValue, uiCompareRules, pOpComparer, uiLanguage, &iCmp))) { goto Exit; } *peBool = (iCmp <= 0 ? XFLM_TRUE : XFLM_FALSE); break; case XFLM_GT_OP: if (RC_BAD( rc = fqCompare( pLValue, pRValue, uiCompareRules, pOpComparer, uiLanguage, &iCmp))) { goto Exit; } *peBool = (iCmp > 0 ? XFLM_TRUE : XFLM_FALSE); break; case XFLM_GE_OP: if (RC_BAD( rc = fqCompare( pLValue, pRValue, uiCompareRules, pOpComparer, uiLanguage, &iCmp))) { goto Exit; } *peBool = (iCmp >= 0 ? XFLM_TRUE : XFLM_FALSE); break; default: *peBool = XFLM_UNKNOWN; rc = RC_SET_AND_ASSERT( NE_XFLM_QUERY_SYNTAX); goto Exit; } } Exit: return( rc); } /*************************************************************************** Desc: Do an arithmetic operator. ***************************************************************************/ RCODE fqArithmeticOperator( FQVALUE * pLValue, FQVALUE * pRValue, eQueryOperators eOperator, FQVALUE * pResult) { RCODE rc = NE_XFLM_OK; FQ_OPERATION * fnOp; FLMUINT uiOffset = 0; if( !isArithOp( eOperator)) { rc = RC_SET( NE_XFLM_SYNTAX); goto Exit; } if (pLValue->eValType == XFLM_MISSING_VAL || pRValue->eValType == XFLM_MISSING_VAL) { pResult->eValType = XFLM_MISSING_VAL; goto Exit; } if( isUnsigned( pLValue)) { if( isUnsigned( pRValue)) { uiOffset = 0; } else if( isSigned( pRValue)) { uiOffset = 1; } else { rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); goto Exit; } } else if( isSigned( pLValue)) { if( isUnsigned( pRValue)) { uiOffset = 2; } else if( isSigned( pRValue)) { uiOffset = 3; } else { rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED); goto Exit; } } fnOp = FQ_ArithOpTable[ ((((FLMUINT)eOperator) - XFLM_FIRST_ARITH_OP) * 4) + uiOffset]; fnOp( pLValue, pRValue, pResult); Exit: return( rc); } /***************************************************************************** Desc: ******************************************************************************/ RCODE F_CollIStream::read( FLMBOOL bAllowTwoIntoOne, FLMUNICODE * puChar, FLMBOOL * pbCharIsWild, FLMUINT16 * pui16Col, FLMUINT16 * pui16SubCol, FLMBYTE * pucCase) { RCODE rc = NE_XFLM_OK; FLMUNICODE uChar; FLMUINT16 ui16WpChar; FLMUINT16 ui16NextWpChar; FLMUINT16 ui16Col; FLMUINT16 ui16SubCol; FLMBOOL bTwoIntoOne; FLMBYTE ucCase; FLMBOOL bAsian; FLMBOOL bLastCharWasSpace = FALSE; FLMUINT64 ui64AfterLastSpacePos = 0; FLMUINT64 ui64CurrCharPos = 0; if (pbCharIsWild) { *pbCharIsWild = FALSE; } // Is this a double-byte (Asian) character set? bAsian = (m_uiLanguage >= FIRST_DBCS_LANG && m_uiLanguage <= LAST_DBCS_LANG) ? TRUE : FALSE; // Get the next character from the stream GetNextChar: ui16WpChar = 0; ui16NextWpChar = 0; ui16Col = 0; ui16SubCol = 0; bTwoIntoOne = FALSE; ucCase = 0; if (m_uNextChar) { uChar = m_uNextChar; m_uNextChar = 0; } else { ui64CurrCharPos = m_pIStream->getCurrPosition(); if( RC_BAD( rc = readCharFromStream( &uChar))) { if (rc != NE_XFLM_EOF_HIT) { goto Exit; } // If we were skipping spaces, we need to // process a single space character, unless we are // ignoring trailing white space. if (bLastCharWasSpace && !(m_uiCompareRules & XFLM_COMP_IGNORE_TRAILING_SPACE)) { // bLastCharWasSpace flag can only be TRUE if either // XFLM_COMP_IGNORE_TRAILING_SPACE is set or // XFLM_COMP_COMPRESS_WHITESPACE is set. flmAssert( m_uiCompareRules & XFLM_COMP_COMPRESS_WHITESPACE); uChar = ASCII_SPACE; rc = NE_XFLM_OK; goto Process_Char; } goto Exit; } } if ((uChar = flmConvertChar( uChar, m_uiCompareRules)) == 0) { goto GetNextChar; } // Deal with spaces if (uChar == ASCII_SPACE) { if (m_uiCompareRules & XFLM_COMP_COMPRESS_WHITESPACE) { bLastCharWasSpace = TRUE; ui64AfterLastSpacePos = m_pIStream->getCurrPosition(); goto GetNextChar; } else if (m_uiCompareRules & XFLM_COMP_IGNORE_TRAILING_SPACE) { if (!bLastCharWasSpace) { bLastCharWasSpace = TRUE; // Save where we are at so that if this doesn't turn out // to be trailing spaces, we can restore this position. ui64AfterLastSpacePos = m_pIStream->getCurrPosition(); } goto GetNextChar; } } else { if (m_uiCompareRules & XFLM_COMP_IGNORE_LEADING_SPACE) { m_ui64EndOfLeadingSpacesPos = ui64CurrCharPos; m_uiCompareRules &= (~(XFLM_COMP_IGNORE_LEADING_SPACE)); } // If the last character was a space, we need to process it. if (bLastCharWasSpace) { // Position back to after the last space, and process a space // character. if (RC_BAD( rc = m_pIStream->positionTo( ui64AfterLastSpacePos))) { goto Exit; } uChar = ASCII_SPACE; bLastCharWasSpace = FALSE; } else if (uChar == ASCII_BACKSLASH) { // If wildcards are allowed, the backslash should be treated // as an escape character, and the next character is the one // we want. Otherwise, it should be treated as // the actual character we want returned. if (m_bMayHaveWildCards) { // Got a backslash. Means the next character is to be taken // no matter what because it is escaped. if (RC_BAD( rc = readCharFromStream( &uChar))) { if (rc != NE_XFLM_EOF_HIT) { goto Exit; } rc = NE_XFLM_OK; uChar = ASCII_BACKSLASH; } } } else if (uChar == ASCII_WILDCARD) { if (m_bMayHaveWildCards && pbCharIsWild) { *pbCharIsWild = TRUE; } } } Process_Char: if (!bAsian) { // Must check for double characters if non-US and non-Asian // character set if (m_uiLanguage != XFLM_US_LANG) { if (RC_BAD( rc = flmWPCheckDoubleCollation( m_pIStream, m_bUnicodeStream, bAllowTwoIntoOne, &uChar, &m_uNextChar, &bTwoIntoOne, m_uiLanguage))) { goto Exit; } } } else { if (RC_BAD( rc = readCharFromStream( &m_uNextChar))) { if (rc == NE_XFLM_EOF_HIT) { rc = NE_XFLM_OK; m_uNextChar = 0; } else { RC_UNEXPECTED_ASSERT( rc); goto Exit; } } } // Convert each character to its WP equivalent if (!flmUnicodeToWP( uChar, &ui16WpChar)) { ui16WpChar = 0; } if (!flmUnicodeToWP( m_uNextChar, &ui16NextWpChar)) { ui16NextWpChar = 0; } // If we have an unconvertible UNICODE character, the collation // value for it will be COLS0 if (!ui16WpChar) { if (!bAsian) { ui16Col = COLS0; } else { if (uChar < 0x20) { ui16Col = 0xFFFF; ui16SubCol = uChar; } else { ui16Col = uChar; ui16SubCol = 0; } } } else { if (!bAsian) { ui16Col = flmWPGetCollation( ui16WpChar, m_uiLanguage); if (bTwoIntoOne) { // Since two characters were merged into one, increment // the collation value by one. In the case of something // like 'ch', there is a collation value between 'c' and // 'd'. flmWPGetCollation would have returned the // collation value for 'c' ... incrementing by one gives // us the proper collation value for 'ch' (i.e., the // collation value between 'c' and 'd'). ui16Col++; } } else { if (flmWPAsiaGetCollation( ui16WpChar, ui16NextWpChar, ui16Col, &ui16Col, &ui16SubCol, &ucCase, !m_bCaseSensitive) == 2) { // Next character was consumed by collation m_uNextChar = 0; } } } if (pui16Col) { *pui16Col = ui16Col; } // Consume m_uNextChar if two characters merged into one if (bTwoIntoOne) { m_uNextChar = 0; } // Subcollation if( pui16SubCol) { if( uChar > 127 && !bAsian) { ui16SubCol = ui16WpChar ? flmWPGetSubCol( ui16WpChar, ui16Col, m_uiLanguage) : uChar; if( !m_bCaseSensitive) { // If the sub-collation value is the original // character, it means that the collation could not // distinguish the characters and sub-collation is being // used to do it. However, this creates a problem when the // characters are the same character except for case. In that // scenario, we incorrectly return a not-equal when we are // doing a case-insensitive comparison. So, at this point, // we need to use the sub-collation for the upper-case of the // character instead of the sub-collation for the character // itself. if( ui16WpChar && ui16SubCol == ui16WpChar) { ui16SubCol = flmWPGetSubCol( flmWPUpper( ui16WpChar), ui16Col, m_uiLanguage); } } } *pui16SubCol = ui16SubCol; } // Case if( pucCase) { if (!m_bCaseSensitive) { *pucCase = 0; } else { if (!bAsian && ui16WpChar) { // flmWPIsUpper() returns FALSE if the character is lower or // TRUE if the character is not lower case. if( flmWPIsUpper( ui16WpChar)) { if( bTwoIntoOne) { if( flmWPIsUpper( ui16NextWpChar)) { ucCase = 0x03; } else { ucCase = 0x10; } } else { ucCase = 0x01; } } } *pucCase = ucCase; } } if (puChar) { *puChar = uChar; } Exit: return( rc); } /*************************************************************************** Desc: ****************************************************************************/ RCODE F_DbSystem::compareUTF8Strings( const FLMBYTE * pucLString, FLMUINT uiLStrBytes, FLMBOOL bLeftWild, const FLMBYTE * pucRString, FLMUINT uiRStrBytes, FLMBOOL bRightWild, FLMUINT uiCompareRules, FLMUINT uiLanguage, FLMINT * piResult) { RCODE rc = NE_XFLM_OK; F_BufferIStream bufferLStream; F_BufferIStream bufferRStream; F_CollIStream lStream; F_CollIStream rStream; if (RC_BAD( rc = bufferLStream.open( pucLString, uiLStrBytes))) { goto Exit; } if( RC_BAD( rc = bufferRStream.open( pucRString, uiRStrBytes))) { goto Exit; } if( RC_BAD( rc = lStream.open( &bufferLStream, FALSE, uiLanguage, uiCompareRules, bLeftWild))) { goto Exit; } if( RC_BAD( rc = rStream.open( &bufferRStream, FALSE, uiLanguage, uiCompareRules, bRightWild))) { goto Exit; } if( RC_BAD( rc = fqCompareCollStreams( &lStream, &rStream, (bLeftWild || bRightWild) ? TRUE : FALSE, uiLanguage, piResult))) { goto Exit; } Exit: return( rc); } /*************************************************************************** Desc: ****************************************************************************/ RCODE F_DbSystem::compareUnicodeStrings( const FLMUNICODE * puzLString, FLMUINT uiLStrBytes, FLMBOOL bLeftWild, const FLMUNICODE * puzRString, FLMUINT uiRStrBytes, FLMBOOL bRightWild, FLMUINT uiCompareRules, FLMUINT uiLanguage, FLMINT * piResult) { RCODE rc = NE_XFLM_OK; F_BufferIStream bufferLStream; F_BufferIStream bufferRStream; F_CollIStream lStream; F_CollIStream rStream; if( RC_BAD( rc = bufferLStream.open( (FLMBYTE *)puzLString, uiLStrBytes))) { goto Exit; } if( RC_BAD( rc = bufferRStream.open( (FLMBYTE *)puzRString, uiRStrBytes))) { goto Exit; } if( RC_BAD( rc = lStream.open( &bufferLStream, TRUE, uiLanguage, uiCompareRules, bLeftWild))) { goto Exit; } if( RC_BAD( rc = rStream.open( &bufferRStream, TRUE, uiLanguage, uiCompareRules, bRightWild))) { goto Exit; } if( RC_BAD( rc = fqCompareCollStreams( &lStream, &rStream, (bLeftWild || bRightWild) ? TRUE : FALSE, uiLanguage, piResult))) { goto Exit; } Exit: return( rc); } /*************************************************************************** Desc: ****************************************************************************/ RCODE XFLMAPI F_DbSystem::utf8IsSubStr( const FLMBYTE * pszString, const FLMBYTE * pszSubString, FLMUINT uiCompareRules, FLMUINT uiLanguage, FLMBOOL * pbExists) { RCODE rc = NE_XFLM_OK; FLMINT iResult = 0; FLMBYTE * pszSearch = NULL; FLMUINT uiSubStringLen = f_strlen( pszSubString); if( RC_BAD( rc = f_alloc( uiSubStringLen + 3, &pszSearch))) { goto Exit; } pszSearch[0] = '*'; f_memcpy( &pszSearch[ 1], pszSubString, uiSubStringLen); pszSearch[ uiSubStringLen + 1] = '*'; pszSearch[ uiSubStringLen + 2] = '\0'; if( RC_BAD( rc = compareUTF8Strings( pszString, f_strlen( pszString), FALSE, pszSearch, uiSubStringLen + 2, TRUE, uiCompareRules, uiLanguage, &iResult))) { goto Exit; } *pbExists = (iResult)?FALSE:TRUE; Exit: if( pszSearch) { f_free( &pszSearch); } return( rc); }